say we have the following code :
class Foo<T> {
lift<R>(): Foo<R> {
const bar = new Foo<T>()
return bar
}
}
why there is no error? Foo<T>
and Foo<R>
may be different type.
CodePudding user response:
TS uses structural type matching and not nominal. This means that 2 types are compatible if their structure is compatible.
You can read about how matching happens for generics here.
The reason your example works is that from a structure point of view there isn't anything that differentiates between Foo<string>
or Foo<number>
for instance. This is gonna work in TS
const a: Foo<string> = new Foo<number>()
This is also the reason why your function works, because Foo<TypeA>
is compatible with Foo<TypeB>
for any TypeA
and TypeB
.
If you add anything else that use T
then the structural compatibility is broken and you get the error you are expecting:
class Foo<T> {
field: T | null = null
lift<R>(): Foo<R> {
const bar = new Foo<T>()
return bar
}
}
Type 'Foo<T>' is not assignable to type 'Foo<R>'.
Type 'T' is not assignable to type 'R'.
'R' could be instantiated with an arbitrary type which could be unrelated to 'T'.(2322)
You can see this in action here