131
votes

I'm having trouble defining interfaces with function members that accept variable amounts of arguments. Take the following object literal as an example:

var obj = {
    func: () => {
        for(var i = 0; i < arguments.length; i++) {
            console.log(arguments[i]);
        }
    }
};

I'd like to be able to define an interface such as:

interface IExample {
    func: ( ??? ) => void;
}

So that the following code can compile without error:

var test = (o: IExample) {
    o.func("a");
    o.func("a", "b");
    o.func("a", "b", "c");
    ...
}
3

3 Answers

239
votes

TypeScript uses the ECMAScript 6 spread proposal,

http://wiki.ecmascript.org/doku.php?id=harmony:spread

but adds type annotations so this would look like,

interface Example {
    func(...args: any[]): void;
}
6
votes

Just to add to chuck's answer, you don't need to have an interface defined as such. You can just do the ... directly in the method:

class Header { constructor(public name: string, public value: string) {} }

getHeaders(...additionalHeaders: Header[]): HttpHeaders {
    let headers = new HttpHeaders();
    headers.append('Content-Type', 'application/json')

    if (additionalHeaders && additionalHeaders.length)
        for (var header of additionalHeaders)
            headers.append(header.name, header.value);

    return headers;
}

Then you can call it:

headers: this.getHeaders(new Header('X-Auth-Token', this.getToken()))

Or

headers: this.getHeaders(new Header('X-Auth-Token', this.getToken()), new Header('Something', "Else"))
0
votes

If the ...args[] argument is not used Typescript still creates an array in the Javascript and copies the arguments to it.

To avoid this unnecessariness you can make a prototype for the function as well as the function, thus:-

function format_n(str: string, ... $n: any[]): string;
function format_n(str: string): string {
    return str.replace(/%(\d+)/g, (_, n) => format_n.arguments[n]);
}