Reputation: 281
I am trying to get items from an array filtered using a supplied constructor using TypeScript. I have not been able to solve the scenario using TypeScript. Am I close? Thanks!
type IConstructor = new (...args: any[] ) => {};
class Apple extends Thing { ... }
class Orange extends Thing { ... }
const items: Thing[] = [
new Apple();
new Orange();
];
let apples = getItemsOfType( Apple ); //Hopefully using the function like this
//Type 'Thing[]' is not assignable to type 'TypeOf[]'.
//Type 'Thing' is not assignable to type 'TypeOf'.
//'TypeOf' could be instantiated with an arbitrary type which could be unrelated to 'Thing'.
//=================================================================================
getItemsOfType<TypeOf extends IConstructor>( TypeConstructor: TypeOf ): TypeOf[] {
return items.filter( item => {
return item instanceof TypeConstructor;
});
}
Upvotes: 0
Views: 50
Reputation: 8340
Well, you were pretty close. Somewhat generic version would look like that:
function getItemsOfType<T extends IConstructor>(ctor: T): InstanceType<T>[] {
return items.filter( (item): item is InstanceType<T> => {
return item instanceof ctor;
});
}
You have to explicitly annotate filter
cb function as type guard to hint typescript about it's 'type-level' meaning.
Or a more generic version with stronger type constraints and no implicit dependency on free variable items
inside the function:
function getItemsOfType<
T extends unknown[],
U extends IConstructor<ArrayElement<T>>
>(items: T, ctor: U): InstanceType<U>[] {
return items.filter( (item): item is InstanceType<U> => {
return item instanceof ctor;
});
}
Upvotes: 1