Skip to content

3.5.1 regression when using this with an index signature of a generic union type #31731

Closed
@justingrant

Description

@justingrant

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)

Playground Link: https://www.typescriptlang.org/play/#src=%2F%2F%20this%20declaration%20fails%20in%203.5.1%20(and%203.6.0-dev.20190602)%2C%20but%20OK%20in%203.4.5%20%0D%0Ainterface%20R%3CA%20%3D%20unknown%3E%20%7B%0D%0A%20%20value%3A%20A%3B%0D%0A%20%20Or%3CB%20extends%20R%3E(b%3A%20B)%3A%20Union%3Cthis%2C%20B%3E%3B%20%2F%2F%20compiler%20error%20on%20%60this%60%0D%0A%7D%0D%0Ainterface%20Union%3CA%20extends%20R%2C%20B%20extends%20R%3E%20extends%20R%3C(A%20%7C%20B)%5B'value'%5D%3E%20%7B%7D%0D%0A%0D%0A%2F%2F%20this%20declaration%20works%20OK%20in%203.4.5%2C%203.5.1%2C%20and%203.6.0-dev.20190602%0D%0A%2F%2F%20The%20only%20difference%20is%20using%20%60A%5B'value'%5D%20%7C%20B%5B'value'%5D%60%20instead%20of%20%60(A%20%7C%20B)%5B'value'%5D%60%0D%0Ainterface%20R2%3CA%20%3D%20unknown%3E%20%7B%0D%0A%20%20value%3A%20A%3B%0D%0A%20%20Or%3CB%20extends%20R2%3E(b%3A%20B)%3A%20Union2%3Cthis%2C%20B%3E%3B%0D%0A%7D%0D%0Ainterface%20Union2%3CA%20extends%20R2%2C%20B%20extends%20R2%3E%20extends%20R2%3CA%5B'value'%5D%20%7C%20B%5B'value'%5D%3E%20%7B%7D

Related Issues: #31691 #31454 #31704 #31439 #30769

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions