52

headjs does some very crazy JavaScript type things to its API. For instance it takes an arbitrary number of strings (not a string array) for a function. Sometimes it ends that same function call, you can optionally end it with a function, for example.

head.js("scripturl1", "scripturl2",...,callback);

You can also (just as easily) do the following

head.js({scriptlabel:"scripturl1"},{scriptlabel2:"scripturl2"},...., callback);

My question is how the HECK do we describe that in a declaration file? I am all ears here as my current pass seems completely wrong.

1
  • I have posted a TypeScript feature request for this as it is a (moderately useful) pattern I have seen elsewhere. Commented Apr 14, 2017 at 10:12

3 Answers 3

98

The TS language spec refers to variable number/spread parameters as "Rest Parameters". An example interface with a function signature that accepts rest params:

interface IExample {
    fn : (...args : any[]) => any;
}

var x : IExample = {
    fn: function(...args : any[]) {
        for (var i = 0, arg; arg = args[i]; i++) {
            console.log(arg);
        }
    }
}

x.fn(1);
x.fn(1, 2);
x.fn("cat", "dog", "mouse");

Unfortunately, there are some limitations. The "Rest Parameter" has to be the last one in a function's signature -- so you won't be able to capture the type of the callback parameter since it is after the repeating parameter.

If it wasn't, you would have been able to do something like this:

var fn = function(cb: Function, ...args : string[]) {
    ...
}
Sign up to request clarification or add additional context in comments.

4 Comments

ya after toialing with it for a while I came to the same conclusion you did.. wish I could have done a ...string:string[], callback:()=>void but alas no luck :-(..) Thanks for the post.
There's actually a cleaner better solution, which is technically not the answer to this actual question (so downvote if you must), but more of a recommendation: Just put your parameters in an object. like this.... myFunc("param1", "param2", {"varParam1": 4 "varParam2": 3 }); This is actually MORE readable code, and if you want to declare an interface for the parameters object, that works cleanly with the above code. So all that is to say, javascript is already so nice in how it handles REST objects, that you don't even need variable argument functions in the language, nor TypeScrip
@ClayFerguson the ...rest pattern is used when you have 1 to n values (perhaps even 0 to n value?) to pass to the function along with other parameters such as a callback. For example: drop(arg1, arg2,...,argn, callback))
@AJP The point i was making is that functions that take many arguments can sometimes be easier to read when you just pass key/value pairs in the form of an object, because you don't have to memorize the 'ordering' of the parameters as you read the code. We've all seen methods like this: doSomething(true, false, false true, true, 0, 10), before and that is bordering on an anti-pattern, imp. Of course once you use key/value pattern it's possibe to misspell a key name, but that can be solved, with a constant or something. Or in TypeScript, even a "type" for the parameter set.
6

You can do something like:

type Action<T extends any[]> = (...args: T) => void

Comments

-7

The declaration is simply:

function foo () { //...

The function arguments part of a function declaration in Javascript is just advisory. When calling a function Javascript allows you to call with less than the declared number of arguments (arguments not passed in defaults to undefined) or with more than the declared number of arguments.

When a function is called, an arguments object is created. The arguments object is a bit like an array (though it is not a proper Array object) that holds each passed in argument.

So, for example, to handle infinite arguments you can simply do:

function foo () {
  for (var n=0; n<arguments.length; n++) {
    alert(arguments[n]);
  }
}

So now you can call foo like:

foo(1,2,3);
foo(1,2,3,4,5,6,7,8);

Beyond that, it is simply a matter of using typeof, itstanceof etc. to detect what type of argument is passed in and process them accordingly.

1 Comment

I understand the javascript behind this, but the actual question was specific for TypeScript... But thank you for the post :-)

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.