Tomas
Tomas

Reputation: 2726

Typescript function taking one or array of objects

We are using simple function declaration quite a lot where function takes either single object or array of objects of some type.

Simple declaration is:

interface ISomeInterface {
    name: string;
}

class SomeClass {
    public names: ISomeInterface[] = [];

    public addNames(names: ISomeInterface | ISomeInterface[]): void {
        names = (!Array.isArray(names)) ? [names] : names;
        this.names = this.names.concat(names);
    }    
}

But TypeScript throws "type is not assignable" error.

Is there better way of doing this? Obviously we could have two separate functions, but I think handling single vs multiple this way is quite fine.

Upvotes: 33

Views: 49286

Answers (4)

Silvermind
Silvermind

Reputation: 5944

You could also use the rest parameter:

interface ISomeInterface {
    name: string;
}

class SomeClass {
    public names: ISomeInterface[] = []; // create an instance if applicable.

    addNames(...names: ISomeInterface[]): void {
        // the names argument will always be an array
        this.names = this.names.concat(names);
    }
}

You can call it like:

addNames(name1); // just pass one
addNames(name1, name2, name3); // pass more comma separated
addNames(...[name1, name2, name3]); // pass an array.

Please note that I removed the function keyword, because otherwise the this keyword inside the body block might lose scope depending on who's calling it.

Upvotes: 22

isvforall
isvforall

Reputation: 8926

You can make it easier

 addNames(names: ISomeInterface | ISomeInterface[]): void {
        this.names = this.names.concat(names);
 } 

From MDN

The concat() method returns a new array comprised of the array on which it is called joined with the array(s) and/or value(s) provided as arguments.

Upvotes: 35

Martin
Martin

Reputation: 16292

I think this is what you want

interface ISomeInterface {
    name: string;
}

class SomeClass {
    public names: ISomeInterface[];

    addNames(names: ISomeInterface | ISomeInterface[]): void {
        names = (names instanceof Array) ? names : [names];
        this.names = this.names.concat(<ISomeInterface[]>names)
    }    
}

You want to use instanceOf, not isArray.

Upvotes: 5

Marie
Marie

Reputation: 2217

The official way typescript handles this is with multiple function signatures, for example:

addNames(names: ISomeInterface): void;
addNames(names: ISomeInterface[]): void;
addNames(names: any): void {
    ...
}

You can see more information in the official handbook here

Upvotes: 2

Related Questions