Reputation: 465
I'm trying to write a function using TypeScript that will allow me to filter a list of objects depending on their type. The result should be a function that will allow me to do either:
filter<Foo>(items);
or
filter(items, Foo);
I've been trying to do it in the following way:
class Foo {
public constructor(public name: string, public type: string) {
}
}
class Bar extends Foo { }
const items: Foo[] = [
new Foo('Foo', 'A'),
new Bar('bar', 'A'),
new Foo('baz', 'B'),
];
const filter = <T extends Foo>(items: any[], typeT: T): T[] => {
return items.filter(item => item instanceof typeT)
};
console.log(filter(items, Foo));
But this doesn't work.
How can I make this work?
Upvotes: 6
Views: 10765
Reputation: 1492
You can simplify things by using the name
property of the class:
class Foo {
public constructor(public name: string, public type: string) {
}
}
class Bar extends Foo { }
const items: Foo[] = [
new Foo('Foo', 'A'),
new Bar('bar', 'A'),
new Foo('baz', 'B'),
];
const filter = (items: Foo[], typeT: Function): Foo[] => {
return items.filter(item => item.constructor.name === typeT.name)
};
console.log(filter(items, Foo)); // Array [ {…}, {…} ]
Upvotes: 0
Reputation: 250406
When you pass in the type you are actually passing in the constructor of the class. Your signature is passing in an instance of T
. You should try:
const filter = <T extends Foo>(items: any[], typeT: new (...params : any[]) => T): T[] => {
return items.filter(item => item instanceof typeT)
};
Note: In your example all the items in the array will pass the filter, because Bar
is derived from Foo
and thus is also an instance of Foo
. If you want only object of type Foo
and not derived, you could use item.constructor == typeT
Upvotes: 5