Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 446
Tomas Avatar asked Mar 02 '16 14:03

Tomas


4 Answers

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.

like image 122
isvforall Avatar answered Oct 25 '22 22:10

isvforall


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.

like image 38
Silvermind Avatar answered Oct 25 '22 21:10

Silvermind


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.

like image 30
Martin Avatar answered Oct 25 '22 21:10

Martin


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

like image 43
Marie Avatar answered Oct 25 '22 21:10

Marie