Description
TS 3.5 broke the runtypes library which uses this
as as a type parameter to a generic method of a generic interface. After simplifying the break into a 4 lines of TS declarations, it looks like the problem is caused by TS failing to correctly resolve types using the index signature of a union type where both sides of the union share the same property name but different generic property types. In 3.4, (A | B)['value']
(where both A
and B
are generic types with a value
property) compiled OK, but in 3.5.1 and 3.6.0-dev.20190602 it triggers a "not assignable to" error when this
is used as one of the type parameters.
FWIW, a slightly different syntax A['value'] | B['value']
works OK in both 3.4 and 3.5.
I see that @ahejlsberg has been working on assignment using this
in #31704 and #31454, so perhaps this issue here is a case that slipped through those PRs?
TypeScript Version: typescript@3.6.0-dev.20190602
Search Terms: this interface typescript recursion recursive union index signature
Code
// this declaration fails in 3.5.1 (and 3.6.0-dev.20190602), but OK in 3.4.5
interface R<A = unknown> {
value: A;
Or<B extends R>(b: B): Union<this, B>; // compiler error on `this`
}
interface Union<A extends R, B extends R> extends R<(A | B)['value']> {}
// this declaration works OK in 3.4.5, 3.5.1, and 3.6.0-dev.20190602
// The only difference is using `A['value'] | B['value']` instead of `(A | B)['value']`
interface R2<A = unknown> {
value: A;
Or<B extends R2>(b: B): Union2<this, B>;
}
interface Union2<A extends R2, B extends R2> extends R2<A['value'] | B['value']> {}
Expected behavior:
No compiler errors (like in 3.4.5)
Actual behavior:
Type 'this' does not satisfy the constraint 'R<unknown>'.
Type 'R<A>' is not assignable to type 'R<unknown>'.
Types of property 'Or' are incompatible.
Type '<B extends R<unknown>>(B: B) => Union<this, B>' is not assignable to type '<B extends R<unknown>>(B: B) => Union<R<unknown>, B>'.
Type 'Union<this, B>' is not assignable to type 'Union<R<unknown>, B>'.
Types of property 'Or' are incompatible.
Type '<B extends R<unknown>>(B: B) => Union<Union<this, B>, B>' is not assignable to type '<B extends R<unknown>>(B: B) => Union<Union<R<unknown>, B>, B>'.
Type 'Union<Union<this, B>, any>' is not assignable to type 'Union<Union<R<unknown>, B>, any>'.
Types of property 'Or' are incompatible.
Type '<B extends R<unknown>>(B: B) => Union<Union<Union<this, B>, any>, B>' is not assignable to type '<B extends R<unknown>>(B: B) => Union<Union<Union<R<unknown>, B>, any>, B>'.
Type 'Union<Union<Union<this, B>, any>, any>' is not assignable to type 'Union<Union<Union<R<unknown>, B>, any>, any>'.
Type 'Union<Union<R<unknown>, B>, any>' is not assignable to type 'Union<Union<this, B>, any>'.
Type 'Union<R<unknown>, B>' is not assignable to type 'Union<this, B>'.ts(2344)