ruhler
ruhler

Reputation: 257

Typescript - Generic Type Variables: Type 'T' is not assignable to type 'T'. Two different types exists with this name exist but they are unrelated

Using typescript 3.0+. See the following simple setup involving generic typed variables:

abstract class BaseClass {
  public abstract merge<T>(model?: T): T;
}

class MyClass extends BaseClass {

  public Value: string;

  public merge<MyClass>(model?: MyClass): MyClass {
    this.Value += model.Value; // <--Property 'Value' does not exist on type 'MyClass'

    return this; // <--Type 'this' is not assignable to type 'MyClass'.
                 //    Type 'MyClass' is not assignable to type 'MyClass'.
                 //    Two different types with this name exist, but they are unrelated.
  }
}

I noted the errors described from the Typescript compiler but these errors don't make sense to me. Why is this wrong?


UPDATED

I understand now that the original code above the merge method in MyClass was defining a new generic typed variable with the same name as "MyClass", which explains the error. So I make the change as seen below. This still produces an error, which I commented above the merge method:

abstract class BaseClass {
  public abstract merge<T>(model?: T): T;
}

class MyClass extends BaseClass {

  public Value: string;

/*
Property 'merge' in type 'MyClass' is not assignable to the same property in base type 'BaseClass'.
  Type '(model?: MyClass) => MyClass' is not assignable to type '<T>(model?: T) => T'.
    Types of parameters 'model' and 'model' are incompatible.
      Type 'T' is not assignable to type 'MyClass'.
*/
  public merge(model?: MyClass): MyClass {
    this.Value += model.Value;

    return this;
  }
}

Why can't I use MyClass as the variable type here? In fact, I can't seem to replace it with any other type that would make it work (e.g. string, number, another class).

Even if I try to define T as a type that extends BaseClass:

abstract class BaseClass {
  public abstract merge<T extends BaseClass>(model?: T): T;
}

This still generates the same error in MyClass. Note that this works fine with TypeScript 2.2.1. I only noticed this not working with any TypeScript version 2.4+.

Upvotes: 1

Views: 3758

Answers (1)

Suma
Suma

Reputation: 34403

The <MyClass> in public merge<MyClass> introduces another type (generic), which is different from the class MyClass, but has the same name. Nothing is known about this generic type, therefore you get the error Property 'Value' does not exist on type 'MyClass'.

The this of type class MyClass, the model is of the generic type.

If your base class defines the method as merge<T>(model?: T): T, the derived class needs to use the same definition. You promised in your base class you will process any parameter (generic T without any restrictions), you cannot restrict it only to MyClass in a derived class.

Upvotes: 4

Related Questions