I have an Inner<T> interface that wraps a value of a generic type:
interface Inner<T> {
v: T;
}
There are different implementations of that Interface:
class SomeInner<T> implements Inner<T> {
constructor(public v: T) {}
some = true;
}
class SomeOtherInner<T> implements Inner<T> {
constructor(public v: T) {}
someOther = true;
}
There is an Outer class that wraps an instance of Inner<T>. I also want to access Inner from time to time. Therefore I keep the actual type of Inner:
class Outer<T, TInner extends Inner<T>> {
constructor(public inner: TInner) { }
getV(): T {
return this.inner.v;
}
}
Unfortunately TS is not able to infer the type of T in Outer - although it knows the type of TInner and its generic type:
const someInnerInst = new SomeInner("foo" as string);
const outerInstOfSomeInner = new Outer(someInnerInst);
const vFromOuter = outerInstOfSomeInner.getV(); // Type: unknown // <- SHOULD BE string
const vFromInner = outerInstOfSomeInner.inner.v; // Type: string
Is there a way to help TypeScript to infer T in Outer?
You can try the full example in the playground.
CodePudding user response:
Typescript will not infer T from the other type parameter. Basically since T does not appear in the parameter list of the constructor no inference will occur for it. You can go about solving this in several ways.
One of the simplest would be to use an intersection to give typescript an inference site for T in the constructor:
class Outer<TInner extends Inner<T>, T> {
constructor(public inner: TInner & Inner<T>) { }
getV(): T {
return this.inner.v;
}
}
You could also use some form of relative typing to extract T from TInner, for example index access types:
class Outer<TInner extends Inner<any>> {
constructor(public inner: TInner) { }
getV(): TInner['v'] {
return this.inner.v;
}
}
Or with conditional types:
type InnerTypeParam<T extends Inner<any>> = T extends Inner<infer U> ? U : never
class Outer<TInner extends Inner<any>> {
constructor(public inner: TInner) { }
getV(): InnerTypeParam<TInner> {
return this.inner.v;
}
}
