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?
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
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
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).
playground
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
Cannot be done yet - purely as a type. There is an open issue that aims to allow passing higher-kind generic types through: https://github.com/microsoft/TypeScript/issues/1213
Its an issue that is a bane to many trying to type highly moddable js-libs (like levelup).
Just to give you a much easier example of something that doesn't work:
interface Dummy<T> {};
declare function getParam<P, T extends Dummy<P>>(a: T): P;
let a = getParam(null as Dummy<string>);
here a is unknown
the only real work around is to move the generic parameter into the dummy interface as a fake property - but then everything passed to this will need that fake property defined too - or you're back to unknown
interface Dummy<T> {
a?: T
};
declare function getParam<P, T extends Dummy<P>>(a: T): T["a"]
let a = getParam(null as Foo<string>);
a is now string
but typescript still has no idea what P
is
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With