I need to implement a type GetClassParameter<T>
that would work like this:
class Foo<T> {
}
type foo = Foo<string>
type x = GetClassParameter<foo>; // should be string
I'm sorry if it's a duplicate, I couldn't find it. I only found a hardcoded solution (source):
type GetFooParameter<T extends Foo<any>> = T extends Foo<infer R> ? R : unknown;
I tried to do something like this:
class Foo<T> {
public value: T;
public value2: string;
constructor (value: T) {
this.value = value;
}
}
type BaseT<T> = {
value: T // if removed, it wouldn't work
}
type GetClassParameter<T extends BaseT<any>> = T extends BaseT<infer R> ? R : unknown;
type x = GetClassParameter<foo> // string - almost works, requires shared property with a T
The above almost works but requires BaseT to have a value: T
property.
Is there a way to do it without hardcoding anything, assuming the target class has only one generic parameter?
Update:
Another take, unsuccessful.
type ClassLike<T> = (new <T>(...args: any[]) => any);
type GetClassParameter<T extends ClassLike<any>> = T extends ClassLike<infer R> ? R : unknown;
type x = GetClassParameter<foo> // error, does not satisfy constraint
Update 2
It's not possible currently. Nevertheless, I tried a hack to define BaseT with value property and then removed it. It doesn't work. I'm adding it as a reference if someone had a similar idea to save you time. playground
Update 3
I'm adding a workaround I'm using to get the class parameter type for 2 classes that have nothing in common (it can be extended to cover more classes just by adding additional conditional).
class Alpha<T> {
private a: T;
}
class Beta<T> {
private b: T;
}
type GetClassParameterForAlphaBeta<T extends Alpha<any> | Beta<any>> =
T extends Alpha<infer R>
? R : T extends Beta<infer R>
? R : unknown;
type alpha = Alpha<string>
type beta = Beta<number>
type x = GetClassParameterForAlphaBeta<alpha> // string
type y = GetClassParameterForAlphaBeta<beta> // number