Home > Blockchain >  Strange behaviour of array filter function in Typescript
Strange behaviour of array filter function in Typescript

Time:10-20

I'm trying to solve problem with filter array function in Typescript, code below:

type Tag = string

type Args = {
  tags?: Tag[]
}

const func = async (args: Args) => {
  if (args.tags) {
    const entities = [
      { tagId: '1' },
      { tagId: '2' }
    ];
    
    const filtered = entities.filter(entity => args.tags.includes(entity.tagId));
    const mapped = args.tags.map(tag => tag   '_test');  
  }
};

This code throws TS2532 error: Object is possibly undefined when I try to filter the entities array. For some reasons TS interpreter thinks that args.tags can be undefined, so include function can't be called. But as you see, there is a check above, also the map function works fine.

What can be wrong here? Any thoughts are welcome.

Thanks.

CodePudding user response:

TypeScript doesn't know that filter's callback runs immediately, so if for example filter's callback ran later (let's say on a setTimeout), your code would crash under a call like this:

const a: Args = { tags: [] };
await func(a);
a.tags = undefined;
// Later, the callback runs and accesses 'includes' of the undefined we just set

You can either use !

entity => args.tags!.includes ...

Or stash the value in a const

const tags = args.tags;
if (tags) {
  // ...
  const filtered = entities.filter(entity => tags.includes ...

CodePudding user response:

type Args = {
  tags?: Tag[] // this means --> tags: Tag[] | undefined
}

Use optional chaining and nullish coalescing inside Array.filter().

const filtered = entities.filter(entity => args?.tags?.includes(entity.tagId));

CodePudding user response:

The entities array is an array of objects, but the TypeScript compiler is inferring the type as any[] and doesn't know that the object will contain the tagId property. Your code should run with the following change:

    const entities: {tagId:string}[] = [

Additionally, you want to account for the potentially undefined tags property in the Args type:

    const filtered = entities.filter(entity => args.tags && args.tags.includes(entity.tagId));

Full code:

type Tag = string;

type Args = {
  tags?: Tag[];
};

const func = async (args: Args) => {
  if (args.tags) {
    const entities: { tagId: string; }[] = [
      { tagId: '1' },
      { tagId: '2' }
    ];

    const filtered = entities.filter(entity => args.tags && args.tags.includes(entity.tagId));
    const mapped = args.tags.map(tag => tag   '_test');
  }
};

I tested this code with ts-node and tsc (with --lib es2016.array.include) and received no errors.

  • Related