rob
rob

Reputation: 18513

Automatically override return type of several functions in a child class in TypeScript

I have a class that has several functions that return a new instance of itself and I want to extend the class and have those functions return an instance of the child class instead. e.g.

class A {
    constructor(public val) {

    }

    getAnother(val): A {
        return new A(val);
    }

    next(): A {
        return this.getAnother(this.val + 1);
    }

    double(): A {
        return this.getAnother(this.val * 2);
    }
}

class B extends A {
    getAnother(val): B {
        return new B(val);
    }

    next(): B {
        return <B>super.next();
    };

    double(): B {
        return <B>super.double();
    };

    getValAsStr() {
        return String(this.val);
    }
}

let b = new B(1);

console.log(b.next().getValAsStr()); // logs "2"

This does what I am trying to accomplish but ideally I wouldn't need to reimplement next() and double() in class B and manually cast the return type. I tried an approach using generics that lets me only override getAnother() in class B but it breaks the polymorphic relationship between A and B

abstract class I<TResult> {
    constructor(public val) {

    }

    abstract getAnother(val): TResult;

    next(): TResult {
        return this.getAnother(this.val + 1);
    }

    double(): TResult {
        return this.getAnother(this.val * 2);
    }
}

class A extends I<A> {
    getAnother(val): A {
        return new A(val);
    }
}

class B extends I<B> {
    getAnother(val): B {
        return new B(val);
    }

    getValAsStr() {
        return String(this.val);
    }
}

Is there an approach that is cleaner than my first approach and that maintains the relationship between A and B in TypeScript?

Upvotes: 0

Views: 1051

Answers (1)

Mike Lischke
Mike Lischke

Reputation: 53492

You can use a polymorphic this.

class A {
    constructor(public val) {

    }

    getAnother(val): this {
        return new A(val);
    }

    next(): this {
        return this.getAnother(this.val + 1);
    }

    double(): this {
        return this.getAnother(this.val * 2);
    }
}

class B extends A {
    getAnother(val): this {
        return new B(val);
    }

    getValAsStr(): string {
        return String(this.val);
    }
}

(untested)

Upvotes: 1

Related Questions