D.Dimitrioglo
D.Dimitrioglo

Reputation: 3663

How to extend factory method in typescript

Context:

I have some class which at some point produces instances of itself, and it works fine. But now I would like to extend that class and realize that I would get an instance of a parent class.

Example:

class Line {
    constructor(protected length: number) {}
    
    divide(into: number): Line[] {
        const size: number = Math.ceil(this.length / into);

        return (new Array(into)).map(() => new Line(size));
    }
}

class BoldLine extends Line {
    constructor(protected length: number, private width: number) {
        super(length);
    }

    getWidth() {
        return this.width;
    }
}

const line: BoldLine = new BoldLine(10, 2);

line.divide(2); // <== I'll get Line[] but would like to have BoldLine[];

Question:

How can I always get the instance of this.constructor class, even after inheritance? And how can I do this in a seamless way, w/o passing constructor name as a parameter for divide method?

Thanks.

Upvotes: 2

Views: 522

Answers (1)

GOTO 0
GOTO 0

Reputation: 47652

Not sure if there is a better approach, but this is how I would do it.

class Line {
    constructor(protected length: number) {}
    
    divide(into: number): this[] {
        const size: number = Math.ceil(this.length / into);

        return (new Array(into)).map(() => new (this.constructor as new (length: number) => this)(size));
    }
}

class BoldLine extends Line {
    constructor(protected length: number, private width) {
        super(length);
    }

    getWidth() {
        return this.width;
    }
}

const line: BoldLine = new BoldLine(10, 2);

line.divide(2);

If you need the width property (which is untyped so it could be anything, including undefined) to be propagated to child classes, then you need an additional factory method for instances of the current class.

class Line {
    constructor(protected length: number) { }

    protected create(length: number): this
    {
        return new Line(length) as this;
    }
    
    divide(into: number): this[] {
        const size: number = Math.ceil(this.length / into);

        return (new Array(into)).map(() => this.create(size));
    }
}

class BoldLine extends Line {
    constructor(protected length: number, private width) {
        super(length);
    }

    protected create(length: number): this
    {
        return new BoldLine(length, this.width) as this;
    }
    
    getWidth() {
        return this.width;
    }
}

const line: BoldLine = new BoldLine(10, 2);

line.divide(2);

Upvotes: 1

Related Questions