6

Now, args is a rest parameter of a tuple type. How to make this constructor also accept arrays, which, when cast to tuple type, will result in a type that is specified in a said constructor?

Can it be done without manual assertion on construction, e.g.:

const args = [3, 5];

let vector = new Vector(...args as [number, number]);

or

const args: [number, number] = [3, 5];

let vector = new Vector(...args);

class Vector {
    x: number;
    y: number;

    constructor(...args: [] | [number] | [number, number]) {
        switch(args.length) {
            case 0:
                this.x = 0;
                this.y = 0;
                break;
            case 1:
                this.x = this.y = args[0];
                break;
            case 2:
                this.x = args[0];
                this.y = args[1];
                break;
        }
    }
}

const args = [3, 5];

let vector = new Vector(...args);

Playground

EDIT: Considering @philipp-fritsche answer, what if I would add these overloads?

class Vector {
    x: number;
    y: number;

    constructor();
    constructor(xy: number);
    constructor(x: number, y: number);
    constructor(arg1?: number, arg2?: number) {
        if(arg1 === undefined) {
            this.x = this.y = 0;
        } else if (arg2 == undefined) {
            this.x = this.y = arg1;
        } else {
            this.x = arg1;
            this.y = arg2;
        }
    }
}

const args = [1, 2];

let vector = new Vector(...args);
4
  • Sounds like you want const args = [3, 5] as const;. Commented Mar 22, 2021 at 6:19
  • @kaya3 is there a way to not do anything outside the Vector class? Commented Mar 22, 2021 at 6:25
  • Uh, well args has type number[] so the only way to edit the Vector class to make this type-check would be for your constructor to accept number[]. Commented Mar 22, 2021 at 6:33
  • 1
    Here you can find overloadings typescriptlang.org/play?#code/… Commented Mar 22, 2021 at 7:38

2 Answers 2

5

There is no benefit here in defining the parameters per rest.

class Vector {
    x: number;
    y: number;

    constructor(x?: number, y?: number) {
        this.x = x ?? 0
        this.y = y ?? x ?? 0
    }
}

const args = [3, 5];

let vector = new Vector(...args);

This works because the type infered for args is number[]. And the elements 0 and 1 of number[] are number | undefined which matches the parameters for Vector.

If you specify ...args: [] | [number] | [number, number], 0, 1 or 2 arguments are allowed. But number[] can have >=0 elements. So this violates your explicit type.

Sign up to request clarification or add additional context in comments.

Comments

0

Considering @philipp-fritsche answer and @captain-yossarian comment, here is the final version, with the little addition.

class Vector {
    x: number;
    y: number;

    constructor();
    constructor(xy?: number);
    constructor(x?: number, y?: number);
    constructor(xy?: Vector);

    constructor(arg1?: number | Vector, arg2?: number) {
        if (arg1 === undefined) {
            this.x = this.y = 0;
        } else if (arg1 instanceof Vector) {
            this.x = arg1.x;
            this.y = arg1.y;
        } else if (arg2 == undefined) {
            this.x = this.y = arg1;
        } else {
            this.x = arg1;
            this.y = arg2;
        }
    }
}

const args = [1, 2];

let vector = new Vector(...args);

console.log(vector);

Playground

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.