Reputation: 1785
I have a Class A
, which has function f
(possibly overwritten by subclasses).
I would like to define a function, g
so that g(cls, ...args)
would only work if cls
is a subclass of A
and args
matches the type signature of cls.f
. Is there a way to do this?
Edit: I have changed the above to reflect the fact that the first argument to g
is actually a constructor of a subclass of A
, rather than an instance.
Upvotes: 2
Views: 659
Reputation: 329808
Sure, you can use tuples in rest/spread types to get this since TS 3.0:
declare class A {
f(...args: any[]): any;
}
declare function g<T extends A>(val: T, ...args: Parameters<T['f']>): void;
declare class B extends A {
f(x: string, y: number): boolean;
}
declare const b: B;
g(b, "hey", 123); // okay
g(b, 123, "hey"); // error
The tuple rest/spread inference is hidden inside the Parameters
type function defined in the standard library as:
type Parameters<T extends (...args: any[]) => any> =
T extends (...args: infer P) => any ? P : never;
Is that what you're looking for?
EDIT: if val
is supposed to be a constructor, then you could do it like this:
declare function g<T extends A>(
val: new(...args:any[])=>T,
...args: Parameters<T['f']>
): void;
declare class B extends A {
f(x: string, y: number): boolean;
}
g(B, "hey", 123); // okay
g(B, 123, "hey"); // error
Or essentially the same thing:
declare function g<T extends new (...args: any[]) => A>(
val: T,
...args: Parameters<InstanceType<T>['f']>
): void;
depending on whether you want T
to be a constructor type or an instance type.
Upvotes: 4