How to reference type of self in Typescript interface (for a IClonable interface)

Very simply set return type as (polymorphic) this:

interface ICloneable {
    clone(): this;
}

In classes, a special type called this refers dynamically to the type of the current class.

Usage:

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

  clone() {
    return new A(this.a) as this;
  }
}

### Important Note

There seems to be an issue with actually using an interface defined like the one above, in a class. The problem is that attempting to override the method in a new class does not work. My suggestion atm would be to hold off on using this syntax or not to use it in an interface and prefer to use a class so that you can provide a basic implementation. It seems that it was introduced mostly to be able to do method chaining properly.

What the OP had initially seems to be the current best way to accomplish this:

interface ICloneable<T> {
  clone(): T;
}

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

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

or even

interface ICloneable {
  clone(): ICloneable;
}

as another answer pointed out.


You are right, using generics is the way to do it, even if it's verbose..

You can also:

interface IClonable {
    clone(): any;
}

or

interface IClonable {
    clone(): any;
    clone<T>(): T;
}

or

interface IClonable {
    clone(): IClonable;
}

But using generics is probably the best way to go.


Edit

@Silvermind comments below made me check the suggested code of clone<T>(): T and I was wrong as it does not compile.
First Here's a code to show what I meant:

class Point implements IClonable {
    private x: number;
    private y: number;
    
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
    
    public clone<T>(): T {
        return <T> new Point(this.x, this.y);
    }
}

var p1 = new Point(1, 2);
var p3 = p1.clone<Point>();

Basically to perform the cast in the clone method instead of casting the returned value.
But <T> new Point(this.x, this.y) produces:

Neither type 'Point` nor type 'T' is assignable to each other

Tags:

Typescript