Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

this type is not assignable to the same property in base type #41181

Closed
helmbold opened this issue Oct 21, 2020 · 6 comments
Closed

this type is not assignable to the same property in base type #41181

helmbold opened this issue Oct 21, 2020 · 6 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@helmbold
Copy link

helmbold commented Oct 21, 2020

TypeScript Version: 4.0.2

Search Terms: this type assignable same property base subtype

The following should work with polymorphic this:

interface Cloneable {
  clone(): this
}

class A implements Cloneable {
  constructor(readonly a: number){}

  clone(): A {
    return new A(this.a)
  }
}

A variant with clone(): this in class A also doesn't work (but with a different error message).

Expected behavior:

The code should compile without error, so that clone in the class A actually returns type A.

Actual behavior:

Property 'clone' in type 'A' is not assignable to the same property in base type 'Cloneable'.
Type '() => A' is not assignable to type '() => this'.
Type 'A' is not assignable to type 'this'.
'A' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'A'.

Playground Link: https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgMIBsD2IJwEbooDeAUMsgljgBQCUAXMmABbADOJAviSZXG22QBBZMAC2AB0JiI4QRmy4CxMhWxswUAK4IwmKNSi4AJtnQBPZHEYgtYvNFpFuqyorqMRpcuSNgtUCDIOADuwtQs7AB0cLSq3JxAA

Related

#283

@MartinJohns
Copy link
Contributor

TypeScript Version: 3.7.x-dev.201xxxxx

The TypeScript version you use is fairly outdated. You should consider updating.


The error is correct, what you want won't work. Just consider this example:

class B extends A { }

const b: B = new B(1);
b.clone(); // Returns A, when it should actually return B (aka "this")

I can't think of a way this would work as you want. When implementing your clone method you can't know the constructor of this because classes are not sealed.

Your best option is to have Cloneable<T> and implement Cloneable<A>.

@helmbold
Copy link
Author

@MartinJohns The version must have been a copy&paste mistake, I tested it with TypeScript 4.0.2.

To your example: I thought that polymorphic this would lead to b.clone() returning an Instance of B. Maybe my understanding is not correct here.

@MartinJohns
Copy link
Contributor

To your example: I thought that polymorphic this would lead to b.clone() returning an Instance of B. Maybe my understanding is not correct here.

But your method doesn't return the polymorphic this. It returns A. You would need to replace the clone(): A with clone(): this.

But then you end up with the other issue that you can't possibly know the constructor of this at the point of implementation. To elaborate on the example:

class B extends A {
  constructor(example: string) {
    super(0);
  }
}

You have no way of knowing the constructor of B when implementing the method in your class A, but this could possibly be B.

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Oct 22, 2020
@RyanCavanaugh
Copy link
Member

Probably what you want to do is this

interface Cloneable<T> {
  clone(): T
}

class A implements Cloneable<A> {
  constructor(readonly a: number){}

  clone(): A {
    return new A(this.a)
  }
}

@helmbold
Copy link
Author

Thanks, @RyanCavanaugh I'm aware of that solution, but hoped to be able to avoid the (somewhat redundant) Type parameter that is always of the same as the class that implements the interface.

@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants