Skip to content

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

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 Anders Hejlsberg (@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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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