Issue
I need your help with this typescript complaint, I have been struggling with this issue for quite a while now. I am trying to filter an array dynamically, but Typescript is complaining. Here is what it said,
(property) Array<T>.filter: {
<S extends {
x: number;
}>(predicate: (value: {
x: number;
}, index: number, array: {
x: number;
}[]) => value is S, thisArg?: any): S[];
(predicate: (value: {
x: number;
}, index: number, array: {
x: number;
}[]) => unknown, thisArg?: any): {
x: number;
}[];
} | {
...;
} | {
...;
}
Here is what I am trying to do:
const shapes ={
rectangles :[
{x :1}
],
ellipses :[
{y :10}
],
polygons :[
{isFinished :true}
]
}
Object.keys(shapes).forEach(shapeKey => {
shapes[shapeKey as keyof typeof shapes].filter(shape => {
//
//
})
})
I am definitely using filter on an array. It should not be complaining. Please, if you know how to fix this, help me
Solution
The problem is that the three different kinds of arrays have nothing in common, so there's no overload of filter that matches the union of the three types of arrays.
You could go the pure type safety route and have some type predicates:
type Rectangle = {
x: number;
};
type Ellipse = {
y: number;
};
type Polygon = {
isFinished: boolean;
};
function isRectangleArray(shapeArray: any[]): shapeArray is Rectangle[] {
return "x" in shapeArray[0];
}
function isEllipseArray(shapeArray: any[]): shapeArray is Ellipse[] {
return "y" in shapeArray[0];
}
function isPolygonArray(shapeArray: any[]): shapeArray is Polygon[] {
return "isFinished" in shapeArray[0];
}
That lets you differentiate between the arrays:
Object.keys(shapes).forEach((shapeKey) => {
const entry = shapes[shapeKey as keyof typeof shapes];
if (entry.length > 0) {
if (isRectangleArray(entry)) {
const result = entry.filter((rect) => {
// ...
});
} else if (isEllipseArray(entry)) {
const result = entry.filter((ell) => {
// ...
});
} else {
const result = entry.filter((polygon) => {
// ...
});
}
}
});
The code for each loop is completely different, because they're dealing with different things.
Alternatively, you could trick TypeScript into thinking that instead of a union of array types (Rectangle[] | Ellipse[] | Polygon[]), you have an array of union types ((Rectangle | Ellipse | Polygon)[]):
Object.keys(shapes).forEach((shapeKey) => {
const entry = shapes[shapeKey as keyof typeof shapes] as (Rectangle | Ellipse | Polygon)[];
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
const result = entry.filter((whatever) => {
// ...
});
});
That's technically incorrect, what you have is a union of distinct array types, but it lets you write a single filter call.
Answered By - T.J. Crowder
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.