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.