TypeScript: Property is not assignable to the same property in generic base type

TypeScript Version: 3.3.3333

Search Terms:

Code

interface IFoo<T> {
    test<T2, P extends keyof T2>(obj: T2, property: P): void;
}

class Foo<T> implements IFoo<T> {
    test<T2, P extends keyof T2>(obj: T2, property: P): void {
    }
}

Expected behavior: No error

Actual behavior:

error TS2416: Property 'test' in type 'Foo<T>' is not assignable to the same property in base type 'IFoo<T>'.
  Type '<T2, P extends keyof T2>(obj: T2, property: P) => void' is not assignable to type '<T2, P extends keyof T2>(obj: T2, property: P) => void'. Two different types with this name exist, but they are unrelated.
    Types of parameters 'property' and 'property' are incompatible.
      Type 'P' is not assignable to type 'keyof T2'.
        Type 'keyof T2' is not assignable to type 'keyof T2'. Two different types with this name exist, but they are unrelated.
          Type 'string | number | symbol' is not assignable to type 'keyof T2'.
            Type 'string' is not assignable to type 'keyof T2'.

Playground Link

The following works with no error:

interface IFoo<T> {
    test<T2, P extends keyof T2>(obj: T2, property: P): void;
    test<T2, P extends keyof T2>(obj: T2, property: P): void;
}

class Foo<T> implements IFoo<T> {
    test<T2, P extends keyof T2>(obj: T2, property: P): void {
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 11
  • Comments: 19 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Same issue with simple subclassing:

class A {
    protected foo?: string;
}

class B extends A {
    protected foo?: string | null;
}

Playground Link

I found what I think is the same bug, here is my alternative minimized repro: https://www.typescriptlang.org/play/#src=interface I<T> { Foo%3F(t%3A T)%3A void%3B } interface X { Foo<T extends I<object>>(c%3A T | I<T>)%3A c is T%3B } class XX implements X { Foo<T extends I<object>>(c%3A T | I<T>)%3A c is T { return false%3B } }

interface I<T> { Foo?(t: T): void; }

interface X { Foo<T extends I<object>>(c: T | I<T>): c is T; }

class XX implements X { Foo<T extends I<object>>(c: T | I<T>): c is T { return false; } }

Using Tsc Version 3.4.3.

@bendavis78 that isn’t a bug

When you overload a method, the overload needs to be compatible with the signature of that method in the extended class. My example was just shorthand for showing that if you have a User, it can be passed into any place that expects a Table, including an assignment.

The goal of TS is to reduce runtime errors, so it’s correct in flagging a bad overload as a compile-time error. This issue is specifically about TS being overzealous with flagging generic overloads, not overloads in general having the wrong arity.

The bug in the original post seems to be fixed as of v4.3.5 playground

I had the same issue, I had to remove those lines :

"strictFunctionTypes": true,
"strictBindCallApply": true

in my tsconfig.json file

I see this issue in TS 3.7.4 as well. If I add another signature, i.e. overloading, then TS is happy.