Inheritance: declare a method that returns the current instance class I have a Vector and 2-dimensional Vector, defined as follows:

    // A general vector
    class Vector {
        values: number[];

        constructor (...values: number[]) {
            this.values = values;
        }

        opposite(): Vector {
            return new Vector(...this.values.map((value, index) =&gt; -value));
        }
    }

    // Two-dimensional vector
    class Vector2 extends Vector {
        constructor(x: number, y: number) {
            super(x, y);
        }

        get x() {
            return this.values[0];
        }

        get y() {
            return this.values[1];
        }
    }


And I have the following code:

    let v = new Vector2(1, 2);
    let w = v.opposite();

    // this is wrong, since w is not a 2-dimensional vector
    console.log(w.x);


How could I solve this inheritance problem elegantly? For me, there are two alternatives:


Override the "opposite" method. I think that this is not a good idea, since currently there is only one method, but there could be a lot of them.

// Two-dimensional vector
class Vector2 extends Vector {
    // ... more methods ... blah blah blah ...
    // overrides the super class method
    opposite(): Vector2 {
        let [x, y] = super.opposite().values;
        return new Vector2(x, y);
    }
}

Create a named constructor. I think this is a good solution, but a bit tedious:

// Two-dimensional vector
class Vector2 extends Vector {
    constructor(x: number, y: number) {
        super(x, y);
    }

    // declare a "named constructor"
    static createFromVector(v: Vector): Vector2 {
        let [x, y] = v.values;
        return new Vector2(x, y);
    }

    // ... more methods ... blah blah blah ...
}

let v = new Vector2(1, 2);
// It's good, but a bit tedious writing constantly "createFromVector"
let w = Vector2.createFromVector(v.opposite());



How do you address this problem?
let v = new Vector2(1, 2);
let w = v.opposite();
// this is wrong, since w is not a 2-dimensional vector
console.log(w.x);



The fact that the .opposite() returns a result that does not fit into the expected use cases, suggests that there is a design issue. In other words, it is a "hint" that Vector2 is not really a Vector in terms of OOP. Why so? Because it does not follow the intuitive contract in which the .opposite() method returns same exact type of the vector as the one on which the method is being invoked. Things will only get worse if one will need to work against a Vector3, Vector4, etc.

There's whole bunch of sources that explain how inheritance is very often not the best way to create new types nor reuse code.

If I was to design the VectorOf2, I would make it wrap the Vector class rather than inherit from it.

class VectorOf2 {
    private _vector: Vector;

    constructor(x: number, y: number) {
        this._vector = new Vector(x, y);
    }

    get x(): number {
        return this._vector[0];
    }

    get y(): number {
        return this._vector[1];
    }

    opposite(): VectorOf2 {
        return new VectorOf2( ... );
    }
}


With this design, each method added to Vector2 is always Vector2-specific and there's no confusion about it. The regular Vector's method can still be reused by VectorOf2 when a new method is implemented.