1

So my issue is pretty straight forward. I have the following code:

abstract class A {
  public abstract fn(): this;
}

class B extends A {
  public fn() {
    return new B();
  }
}

which is supposed to mean that whichever class inherits from A is supposed to return an instance of itself when fn is called but running this code I get an error: Property 'fn' in type 'B' is not assignable to the same property in base type 'A'.

3 Answers 3

2

Titian explained why it is not allowed. Here's how you can implement it in safer way:

abstract class A<T> {
    public abstract fn(): T;
}

class B extends A<B> {
    public fn() {
        return new B();
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yeah, that is type safe, but suffers from the inability to extend it past B :(
1

The specific error you are getting is cause by the fact that you don't have an annotation on fn in B.This means fn will return B not this in the derived class.

The only value you can really return (without type assertions) from a function returning this is this. Consider the following:

abstract class A {
    public abstract fn(): this;
}

class B extends A {
    public fn(): this {
        return new B();
    }
}

class C extends B {
    m() { }
}
new C().fn().m(); // runtime error since fn returned B instead of C

You can use a type assertion but it is not really type safe as demonstrated above:

class B extends A {
    public fn(): this {
        return new B() as this;
    }
}

2 Comments

That was a great explanation, thanks a lot! I guess I will have to change the structure of my code since, as you said, there is not a good type-safe way of achieving what I want. Will also accept the answer once SO lets me.
@Komninos you want to correctly type a clone function basically. I don't think there is a good way to model this in typescript. The function would have to be typed in such a way that all derived types must override it, abstract will only make you override the first level classes ..
0

But you're not returning and instance of itself, you're returning a new instance:

abstract class A {
  public abstract fn(): this;
}

class B extends A {
  public fn() {
    return this;
  }
}

Or change return:

abstract class A {
  public abstract fn(): A;
}

class B extends A {
  public fn() {
    return new B();;
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.