Proposal: Variadic Kinds -- Give specific types to variadic functions

Variadic Kinds
Give Specific Types to Variadic Functions
This proposal lets Typescript give types to higher-order functions that take a variable number of parameters.
Functions like this include concat, apply, curry, compose and almost any decorator that wraps a function.
In Javascript, these higher-order functions are expected to accept variadic functionsas arguments.
With the ES2015 and ES2017 standards, this use will become even more common as programmers start using spread arguments and rest parameters for both arrays and objects.
This proposal addresses these use cases with a single, very general typing strategy based on higher-order kinds.
This proposal would completely or partially address several issues, including:

#5331 -- Tuples as types for rest ...arguments
#4130 -- Compiler incorrectly reports parameter/call target signature mismatch when using the spread operator
#4988 -- Tuples should be clonable with Array.prototype.slice()
#1773 -- Variadic generics?
#3870 -- Rest types in generics for intersection types.
#212 -- bind, call and apply are untyped (requires #3694's this-function types).
#1024 -- Typed ...rest parameters with generics

I'll be updating this proposal on my fork of the Typescript-Handbook: sandersn/TypeScript-Handbook@76f5a75868de3fb1ad4dbed5db437a8ab61a2698
I have an in-progress implementation at sandersn/TypeScript@f3c327aef22f6251532309ba046874133c32f4c7 which currently has the simple parts of the proposal implemented.
It supercedes part 2 of my previous proposal, #5296.
Edit: Added a section on assignability. I'm no longer sure that it strictly supercedes #5296.
Preview example with curry
curry for functions with two arguments is simple to write in Javascript and Typescript:
function curry(f, a) {
    return b => f(a, b);
}

and in Typescript with type annotations:
function curry<T, U, V>(f: (t: T, u: U) => V, a:T): (b:U) => V {
    return b => f(a, b);
}

However, a variadic version is easy to write in Javascript but cannot be given a type in TypeScript:
function curry(f, ...a) {
    return ...b => f(...a, ...b);
}

Here's an example of using variadic kinds from this proposal to type curry:
function curry<...T,...U,V>(f: (...ts: [...T, ...U]) => V, ...as:...T): (...bs:...U) => V {
    return ...b => f(...a, ...b);
}

The syntax for variadic tuple types that I use here matches the spread and rest syntax used for values in Javascript.
This is easier to learn but might make it harder to distinguish type annotations from value expressions.
Similarly, the syntax for concatenating looks like tuple construction, even though it's really concatenation of two tuple types.
Now let's look at an example call to curry:
function f(n: number, m: number, s: string, c: string): [number, number, string, string] {
    return [n,m,s,c];
}
let [n,m,s,c] = curry(f, 1, 2)('foo', 'x');
let [n,m,s,c] = curry(f, 1, 2, 'foo', 'x')();

In the first call,
V = [number, number, string, string]
...T = [number, number]
...U = [string, string]

In the second call,
V = [number, number, string, string]
...T = [number, number, string, string]
...U = []

Syntax
The syntax of a variadic kind variable is ...T where T is an identifier that is by convention a single upper-case letter, or T followed by a PascalCase identifier.
Variadic kind variables can be used in a number of syntactic contexts:
Variadic kinds can be bound in the usual location for type parameter binding, including functions and classes:
function f<...T,...U>() {}
}
class C<...T> {
}

And they can be referenced in any type annotation location:
function makeTuple<...T>(ts:...T): ...T {
    return ts;
}
function f<...T,...U>(ts:...T): [...T,...U] {
    // note that U is constrained to [string,string] in this function
    let us: ...U = makeTuple('hello', 'world');
    return [...ts, ...us];
}

Variadic kind variables, like type variables, are quite opaque.
They do have one operation, unlike type variables.
They can be concatenated with other kinds or with actual tuples.
The syntax used for this is identical to the tuple-spreading syntax, but in type annotation location:
let t1: [...T,...U] = [...ts,...uProducer<...U>()];
let t2: [...T,string,string,...U,number] = [...ts,'foo','bar',...uProducer<...U>(),12];

Tuple types are instances of variadic kinds, so they continue to appear wherever type annotations were previously allowed:
function f<...T>(ts:...T): [...T,string,string] {
    // note the type of `us` could have been inferred here
    let us: [string,string] = makeTuple('hello', 'world');
    return [...ts, ...us];
}

let tuple: [number, string] = [1,'foo'];
f<[number,string]>(tuple);

Semantics
A variadic kind variable represents a tuple type of any length.
Since it represents a set of types, we use the term 'kind' to refer to it, following its use in type theory.
Because the set of types it represents is tuples of any length, we qualify 'kind' with 'variadic'.
Therefore, declaring a variable of variadic tuple kind allows it to take on any single tuple type.
Like type variables, kind variables can only be declared as parameters to functions, classes, etc, which then allows them to be used inside the body:
function f<...T>(): ...T {
    let a: ...T;
}

Calling a function with arguments typed as a variadic kind will assign a specific tuple type to the kind:
f([1,2,"foo"]);

Assigns the tuple type ...T=[number,number,string]...T.  So in this application off,let a:...Tis instantiated aslet a:[number,number,string]. However, because the type ofais not known when the function is written, the elements of the tuple cannot be referenced in the body of the function. Only creating a new tuple froma` is allowed.
For example, new elements can be added to the tuple:
function cons<H,...Tail>(head: H, tail: ...Tail): [H,...Tail] {
    return [head, ...tail];
}
let l: [number, string, string, boolean];
l = cons(1, cons("foo", ["baz", false]));

Like type variables, variadic kind variables can usually be inferred.
The calls to cons could have been annotated:
l = cons<number,[string,string,boolean]>(1, cons<string,[string,boolean]>("foo", ["baz", false]));

For example, cons must infer two variables, a type H and a kind ...Tail.
In the innermost call, cons("foo", ["baz", false]), H=string and ...Tail=[string,boolean].
In the outermost call, H=number and ...Tail=[string, string, boolean].
The types assigned to ...Tail are obtained by typing list literals as tuples -- variables of a tuple type can also be used:
let tail: [number, boolean] = ["baz", false];
let l = cons(1, cons("foo", tail));

Additionally, variadic kind variables can be inferred when concatenated with types:
function car<H,...Tail>(l: [H, ...Tail]): H {
    let [head, ...tail] = l;
    return head;
}
car([1, "foo", false]);

Here, the type of l is inferred as [number, string, boolean].
Then H=number and ...Tail=[string, boolean].
Limits on type inference
Concatenated kinds cannot be inferred because the checker cannot guess where the boundary between two kinds should be:
function twoKinds<...T,...U>(total: [...T,string,...U]) {
}
twoKinds("an", "ambiguous", "call", "to", "twoKinds")

The checker cannot decide whether to assign

...T = [string,string,string], ...U = [string]
...T = [string,string], ...U = [string,string]
...T = [string], ...U = [string,string,string]

Some unambiguous calls are a casualty of this restriction:
twoKinds(1, "unambiguous", 12); // but still needs an annotation!

The solution is to add type annotations:
twoKinds<[string,string],[string,string]>("an", "ambiguous", "call", "to", "twoKinds");
twoKinds<[number],[number]>(1, "unambiguous", 12);

Uncheckable dependencies between type arguments and the function body can arise, as in rotate:
function rotate(l:[...T, ...U], n: number): [...U, ...T] {
    let first: ...T = l.slice(0, n);
    let rest: ...U = l.slice(n);
    return [...rest, ...first];
}
rotate<[boolean, boolean, string], [string, number]>([true, true, 'none', 12', 'some'], 3);

This function can be typed, but there is a dependency between n and the kind variables: n === ...T.length must be true for the type to be correct.
I'm not sure whether this is code that should actually be allowed.
Semantics on classes and interfaces
The semantics are the same on classes and interfaces.
TODO: There are probably some class-specific wrinkles in the semantics.
Assignability between tuples and parameter lists
Tuple kinds can be used to give a type to rest arguments of functions inside their scope:
function apply<...T,U>(ap: (...args:...T) => U, args: ...T): U {
    return ap(...args);
}
function f(a: number, b: string) => string {
    return b + a;
}
apply(f, [1, 'foo']);

In this example, the parameter list of f: (a: number, b:string) => string must be assignable to the tuple type instantiated for the kind ...T.
The tuple type that is inferred is [number, string], which means that (a: number, b: string) => string must be assignable to (...args: [number, string]) => string.
As a side effect, function calls will be able to take advantage of this assignability by spreading tuples into rest parameters, even if the function doesn't have a tuple kind:
function g(a: number, ...b: [number, string]) {
    return a + b[0];
}
g(a, ...[12, 'foo']);

Tuple types generated for optional and rest parameters
Since tuples can't represent optional parameters directly, when a function is assigned to a function parameter that is typed by a tuple kind, the generated tuple type is a union of tuple types.
Look at the type of h after it has been curried:
function curry<...T,...U,V>(cur: (...args:[...T,...U]) => V, ...ts:...T): (...us:...U) => V {
    return ...us => cur(...ts, ...us);
}
function h(a: number, b?:string): number {
}
let curried = curry(h, 12);
curried('foo'); // ok
curried(); // ok

Here ...T=([number] | [number, string]), so curried: ...([number] | [number, string]) => number which can be called as you would expect. Unfortunately, this strategy does not work for rest parameters. These just get turned into arrays:
function i(a: number, b?: string, ...c: boolean[]): number {
}
let curried = curry(i, 12);
curried('foo', [true, false]);
curried([true, false]);

Here, curried: ...([string, boolean[]] | [boolean[]]) => number.
I think this could be supported if there were a special case for functions with a tuple rest parameter, where the last element of the tuple is an array.
In that case the function call would allow extra arguments of the correct type to match the array.
However, that seems too complex to be worthwhile.
Extensions to the other parts of typescript

Typescript does not allow users to write an empty tuple type.
However, this proposal requires variadic kinds to be bindable to a empty tuple.
So Typescript will need to support empty tuples, even if only internally.

Examples
Most of these examples are possible as fixed-argument functions in current Typescript, but with this proposal they can be written as variadic.
Some, like cons and concat, can be written for homogeneous arrays in current Typescript but can now be written for heteregoneous tuples using tuple kinds.
This follows typical Javascript practise more closely.
Return a concatenated type
function cons<H,...T>(head: H, tail:...T): [H, ...T] {
    return [head, ...tail];
}
function concat<...T,...U>(first: ...T, ...second: ...U): [...T, ...U] {
    return [...first, ...second];
}
cons(1, ["foo", false]); // === [1, "foo", false]
concat(['a', true], 1, 'b'); // === ['a', true, 1, 'b']
concat(['a', true]); // === ['a', true, 1, 'b']

let start: [number,number] = [1,2]; // type annotation required here
cons(3, start); // == [3,1,2]

Concatenated type as parameter
function car<H,...T>(l: [H,...T]): H {
    let [head, ...tail] = l;
    return head;
}
function cdr<H,...T>(l: [H,...T]): ...T {
    let [head, ...tail] = l;
    return ...tail;
}

cdr(["foo", 1, 2]); // => [1,2]
car(["foo", 1, 2]); // => "foo"

Variadic functions as arguments
function apply<...T,U>(f: (...args:...T) => U, args: ...T): U {
    return f(...args);
}

function f(x: number, y: string) {
}
function g(x: number, y: string, z: string) {
}

apply(f, [1, 'foo']); // ok
apply(f, [1, 'foo', 'bar']); // too many arguments
apply(g, [1, 'foo', 'bar']); // ok

function curry<...T,...U,V>(f: (...args:[...T,...U]) => V, ...ts:...T): (...us: ...U) => V {
    return us => f(...ts, ...us);
}
let h: (...us: [string, string]) = curry(f, 1);
let i: (s: string, t: string) = curry(f, 2);
h('hello', 'world');

function compose<...T,U,V>(f: (u:U) => U, g: (ts:...T) => V): (args: ...T) => V {
    return ...args => f(g(...args));
}
function first(x: number, y: number): string {
}
function second(s: string) {
}
let j: (x: number, y: number) => void = compose(second, first);
j(1, 2);

TODO: Could f return ...U instead of U?
Decorators
function logged<...T,U>(target, name, descriptor: { value: (...T) => U }) {
    let method = descriptor.value;
    descriptor.value = function (...args: ...T): U {
        console.log(args);
        method.apply(this, args);
    }
}

Open questions

Does the tuple-to-parameter-list assignability story hold up? It's especially shaky around optional and rest parameters.
Will the inferred type be a union of tuples as with the optional-parameter case? Because bind, call and apply are methods defined on Function, their type arguments need to be bound at function-creation time rather than the bind call site (for example). But this means that functions with overloads can't take or return types specific to their arguments -- they have to be a union of the overload types. Additionally, Function doesn't have a constructor that specifies type arguments directly, so there's really no way provide the correct types to bind et al. TODO: Add an example here. Note that this problem isn't necessarily unique to variadic functions.
Should rest parameters be special-cased to retain their nice calling syntax, even when they are generated from a tuple type? (In this proposal, functions typed by a tuple kind have to pass arrays to their rest parameters, they can't have extra parameters.)

+1, this is really useful for functional programming in TypeScript! How would this work with optional or rest arguments? More concrete, can the compose function be used on functions with rest arguments or optional arguments?

Good point. I think you could assign the smallest allowed tuple type to an optional-param function since tuple are just objects, which allow additional members. But that's not ideal. I'll see if I can figure out the compose example and then I'll update  the proposal.

Actually union types would probably work better. Something like
function f(a: string, b? number, ...c: boolean[]): number;
function id<T>(t: T): T;
let g = compose(f, id): (...ts: ([string] | [string, number] | [string, number, boolean[]]) => number

g("foo"); // ok
g("foo", 12); // ok
g("foo", 12, [true, false, true]); // ok

This still breaks rest parameters, though.

@ahejlsberg, you had some ideas how tuple kinds would work, I think.

So :+1: on this.  For information this is related to (and would fulfill) #3870.  We have tried to implement a compose type API in TypeScript but are having to work around some of the limitations noted in this proposal.  This would certainly solve some of those problems!
It seems though that sometimes you may want to "merge" such tuple types instead of persisting them, especially with something like compose.  For example:
function compose<T, ...U>(base: T, ...mixins: ...U): T&U {
    /* mixin magic */
}

Also, in a lot of your examples, you have been using primitives.  How would you see something more complex working, especially if there are conflicts?

Unfortunately this proposal as-is does not address #3870 or the type composition, since the only composition operator for tuple kinds is [T,...U]. You could also write this as T + ...U (which is more indicative of what happens to the types), but #3870 and your type composition library need T & ...U. I think that might be possible, but I need to understand @JsonFreeman's and @jbondc's ideas from #3870 first. I'll expand the proposal if I can figure out how it should work.
Note: I decided to go with the syntax [...T, ...U] because it looks like the equivalent value spreading syntax, but T + ...U is more indicative of what's happening with the types. If we end up with both, then + and & might be the operators to use.

Big :+1: on this!

+ fits nicely JS as a concatenation of types. The difference with & and + would be that concatenation creates a new type?
Would make sense to add - too as in #4183. You can still have trace preservation in both of those, the user only sees the merged/newType.

+1 awesome! It would allow to express such things much more expressive and lightweight.

My point in #3870 seems to be an issue here. Specifically, I worry about inferring type arguments for variadic type parameters.
Type argument inference is a rather complicated process, and it has changed in subtle ways over time. When arguments are matched against parameters in order to infer type type arguments, there are no guarantees about the order in which candidates are inferred, nor how many candidates are inferred (for a given type parameter). This has generally not been a problem because the result surfaced to the user does not (in most cases) expose these details. But if you make a tuple type out of the inference results, it certainly does expose both the order and the count of the inferences. These details were not intended to be observable.
How serious is this? I think it depends on how exactly the inference works. What is the result of the following:
function f<...T>(x: ...T, y: ...T): ...T { }
f(['hello', 0, true], [[], 'hello', { }]); // what is the type returned by f?

@jbondc, - seems like a good idea. I'll keep it in mind but not explore it here, because I think we should introduce new type operators one at a time. Both & and + create new types, but & creates an intersection type whereas + creates a new tuple type (which is why I prefer the syntax [T,...U] instead of T + ...U, because [T,U] already does this for types).
@JsonFreeman l think it's OK to do one of two things with repeated kind parameters:

Union the types: f(['hello', 1], [1, false]): [string | number, number | boolean]
Disallow inference of repeated tuple kind parameters, particularly if type argument inference proves complicated. Something like this:

f(['hello', 1], [1, false]) // error, type arguments required
f<[string, number]>(['hello', 1], [1, false]) // error, 'number' is not assignable to 'string'
f<[string | number, number | boolean]>(['hello', 1], [1, false]); // ok

I think real libraries (like the reactive extensions @Igorbek linked to) will usually only have one tuple kind parameter so even though neither (1) nor (2) are particularly usable, it shouldn't impact real-world code much.
In the examples above, curry is the hardest to infer -- you have to skip f: (...args:[...T,...U]) => V, infer ...ts:...T, then go back and set ...U to what's left after consuming ...T from f's parameters.
I've started prototyping this (sandersn/TypeScript@1d5725d), but haven't got that far yet. Any idea if that will work?

I would err on the side of disallowing anything where the semantics is not clear (like repeated inferences to the same spreaded type parameter). That allays my concern above as well.
I can't think of a good mechanism for typing query. As you point out, you have to skip the parameter list of the first function to consume the ...T argument and then see what's left over. There would have to be some policy to postpone inferences to a spreaded type parameter if it's not final in its list. It could get messy.
That said, I think this is worth a try. There is high demand for the feature.

I think you would have to skip multiple tuple kinds that occur in the same context (eg top-level like (...T,string,...U) => V or concatenated like [...T,...U,...T]). Then you can make multiple passes on the skipped kinds, eliminating already-inferred kinds and re-skipping kinds that are still ambiguous. If at any point no single kind is available for inference, stop and return an error.
So, yeah. Complicated.

You may be able to draw inspiration from a similar problem. It is actually somewhat similar to the problem of inferring to a union or intersection. When inferring to a union type that includes a type parameter that is a member of the inference context, as in function f<T>(x: T | string[]), you don't know whether to infer to T. The intended manifestation of the union type may have been string[]. So typescript first infers to all other constituents, and then if no inferences were made, infers to T.
In the case of intersection, it's even harder because you may have to split the type of the argument across the different intersection constituents. Typescript doesn't make inferences to intersection types at all.
What if you only allowed spreading tuple if it is the last type in its sequence? So [string, ...T] would be allowed, but [...T, string] would not be?

If I understand correctly, this would actually solve the mixin story in TypeScript. Am I correct in this understanding?

Maybe. Can you give an example? I'm not fluent with mixin patterns.

The syntax of a variadic kind variable is ...T where T is an identifier that is by convention a single upper-case letter, or T followed by a PascalCase identifier.

Can we leave the case of a type parameter identifier up to the developer?

@aleksey-bykov +1. I don't see a reason why that shouldn't be the case.

Developers with Haskell background would appreciate that.

Sorry, that sentence can be parsed ambiguously. I meant 'or' to parse tightly: "by convention (a single upper-case letter || T followed by a PascalCase identifier)". I'm not proposing constraining the case of the identifiers, just pointing out the convention.
For what it's worth, though, I have a Haskell background and I don't like breaking conventions of the language I'm writing in.

Sorry for derailing. My last curious question (if you don't mind me asking) what is the "convention" of TypeScript that might get broken and who is concerned?

@sandersn
This should type check, assuming T & ...U means T & U & V & ... (which is the intuitive behavior).
function mixin<T, U, ...V>(obj: T, src: U, ...srcs: ...V): T & U & ...V {
  if (arguments.length < 2) return <T & U & ...V> obj

  for (const key of Object.keys(src)) {
    (<any> obj)[key] = (<any> src)[key]
  }

  if (arguments.length === 2) return <U> obj
  return mixin<T, ...V>(obj, ...srcs)
}

@aleksey-bykov the convention I'm talking about is the case of type parameter identifiers. Who is concerned? People who have to read new Typescript code they've never seen before -- conventions help new readers understand new code faster.

@sandersn What @aleksey-bykov got the impression of was that the following would be syntactically invalid:
function assign<a, b, ...cs>(x: a, y: b, ...zs: ...cs): a & b & ...cs;

@isiahmeadows & and | operations over kinds are not covered in this proposal, although I should add them to open questions/future work if I haven't. Right now the only proposed operator is concatenation: [THead, ...TTail].
One difference is that concatenation still produces a tuple type while & and | produce intersection and union types respectively.

@sandersn My assign example in TypeScript would be trivial to change with that.

Although:

Intersection would be similar to concatenation, although it's more like concatenating dictionaries than concatenating lists. Variadic types might be implemented on top of existing machinery there.
Union would be like intersection, except it's only keeping the common parts. Once again, variadic types might be implemented on top of existing machinery.

@isiahmeadows An intersection is not in general a concatenation of dictionaries. That's only true for an intersection of object types, but not for example an intersection of unions. Unions are also not the same as just taking the properties objects have in common. The two are better characterized by the set of values inhabiting them.

@sandersn I'm a little confused about type argument inference with variadic kinds. What should be inferred here?
function foo<...T>(...rest: ...T): ...T { }
foo('str', 0, [0]);

Is the result [string, number, number[]]? That would mean you have to rely on type argument inference adding candidates in a left-to-right order, which is not a trivial assumption.

I know that is an experimental / early proposal, but we could discuss ...T syntax for rest parameters. From my perspective, it doesn't really work.
So the proposed syntax is:
declare function f<...T>(...a: ...T);

let's compare with existing syntax of rest parameters:
declare function f(...a: number[]);

so the type of a parameter that catches rest arguments is number[], so we can clearly understand that is an array. By analogy, I can infer that ...T from the proposal represents an array as well. But that's not very obvious.
Next, let's say we could define more restrictive rest parameters:
declare function f(...a: [number, string]);
// same as
declare function f(c: number, d: string); // or very close to

So now, we still see that type of a is a tuple (which is an array).
My proposal is to use more consistent way to treat notion of ...T to represent as a "some abstract ordered list of types". And use it in the same way how we use spread operator:
var a: [number, string] = [1, "1"];
var b = [true, ...a]; // this must be [boolean, number, string], but it doesn't work :)

So ...a in case of variable, is just 1, "1".
My syntax for defining rest parameters by ...T notion:
declare function f<...T>(...a: [...T]);
declare function g<H, ...T>(head: H, ...tail: [...T]): [H, ...T];

For me it makes much more sense.

@Igorbek I've been running on the assumption declare function f<...T>(...a: ...T); already worked like that. But I don't see declare function f(...a: [number, string]); getting much use.

To be more clear.
Originally proposed syntax for rest parameters:
function func<...T>(...a: ...T)

If I can do this
function g<...T>(...a: ...T): [number, ...T] { ... }

So I will be able do this:
function f<...T>(...a: ...T): [...T] { return a; }

So the type of a is [...T] (we return so), but we defined it as ...T in the signature.
We could say that ...T and [...T] are same, but it doesn't work in case of variables.
For variables:
var a = [1, 2];
[a] === [[1,2]];
[...a] === [1, 2];
f(...a) === f(1, 2)
...a === 1, 2 // virtually

If we apply same to standard rest parameters
function f(...a: number[]): number[] { return a; }

the type of a is number[] (by return type), same as it was defined in the signature.

@isiahmeadows yes, function f(...a: [number, string]) doesn't work. I just developed thoughts about how we can treat rest parameters.

So, going further. To explicitly define type parameters, the following syntax was proposed:
function f<...T, ...U>()
f<[number, string], [boolean, number]>();

Turns to:
f<...[number, string], ...[boolean, number]>();

So this might work too:
function g<T1, T2, T3>()

g<A, B, C>();
// same as
g<...[A, B, C]>();
g<...[A], ...[B, C]>();
g<...[A], B, C, ...[]>();

@JsonFreeman that is how my prototype works, yes. But I'm not familiar enough with the type inference algorithm to understand why it works. In other words, the question is not whether left-to-right inference is a trivial assumption but a correct one. For the identity case the answer is yes but I don't know if you can construct cases where the answer is no.
Also can you work through an example of an exposed set of type inference candidates? Like I said, I don't understand the working of the inference algorithm very well, so an example would help me to see what you mean.

And even better:
function<...T>(...a: T): T;
// same as
function<...T>(...a: [...T]): T;

I suggest to prefix [] to the type identifier to signify the rest of type params.
function fn<R, []T>(...a:[]T): R;

@aleksey-bykov I'm actually of the opposite opinion on that. It doesn't fit with the existing rest parameter syntax, so I believe it's also less clear from a glance.

[...T]/T as a rest array parameter type seems much better for me. Once again, compare with array and their sprad operator:

arrays
types (from proposal)
types (my update)

var x = [1,2]
no
T = [T1, T2]

[0, ...x] === [0,1,2]
[T0, ...T] === [T0, T1, T2]
[T0, ...T] === [T0, T1, T2]

f(x) === f([1, 2])
no
f<T>() === f<[T1, T2]>()

f(...x) === f(1, 2)
f<...T>() === f<[T, T2]> ?
f<...T>() === f<T1, T2>

f(0, ...x) === f(1, 2)
f<T0, ...T>() === f<T0, [T, T2]> ?
f<T0, ...T>() === f<T0, T1, T2>

From proposal
function g<...T>(...x: ...T) {
 // being called as g(1, "a");
  var a: ...T; // [number, string] ?
  var b: [number, ...T]; // [number, number, string]
  var c: [...T]; // [number, string] - same as a ? so [...T] is same as ...T - weird
}

From my update
```ts
function g<...T>(...x: T) {
 // being called as g(1, "a");
  var a: T; // [number, string]
  var b: [number, ...T]; // [number, number, string]
  var c: [...T]; // [number, string]
}

The update looks nicer now IMO. I get the purity, but I'm also looking at the pragmatic aspect as well. If you want theoretical purity, I don't think TypeScript is the best language for that, anyways (maybe try PureScript or some other Haskell derivative).

The update looks nicer now IMO. Lists to represent types sounds very nice, but even typed Lisps don't go that far (homoiconic types, anyone? :smile:).
I get the allure of purity, but I'm also looking at the pragmatic aspect as well. Lists would also be relatively easy to implement on their own, but it doesn't fit in with the rest of the language. It's almost like the numerous attempts to implement monads in Java (the language) or lambdas in C - they always turn out incredibly ugly and hackish.

@sandersn I can try to explain what I mean by exposing the list of candidates. Type argument inference generates a list of candidates for each type parameter. Then it checks if any candidate is a supertype of all the others, and if so, that candidate is the winner. So in the following example:
function foo<T>(a: T, b: T): T {}
foo(["hi", 0], ["", ""]);

The arguments will be typed, and then inferred to each parameter. Two candidates will be generated, namely (string | number)[] and string[]. But the first one will win because it is a supertype of the second. And as a result, the user never observes that string[] was ever in the picture. There is one inference for T, and all other candidates are invisible. This means that there are two things invisible to the user, namely the order of the candidates and the multiplicities of the candidates.
Here is an issue with the multiplicities if you rely on the candidate list as your list of elements in the tuple denoted by ...T:
function foo<...T>(...rest: ...T): ...T
foo(0, 1);

I think you would want to infer [number, number] for T given the intent of your proposal as I understand it. But because of the contains check in line https://github.com/Microsoft/TypeScript/blob/master/src/compiler/checker.ts#L6256, the number candidate will only be added once, and T will be inferred as [number]. This is the mulitiplicity issue I was talking about.
As for the order, it is left to right. But there are multiple passes, and arguments will be reprocessed if they contain function expressions that will be contextually typed. If there are n arguments containing contextually typed function expressions, then there are n + 1 passes over the arguments. An example is Array.prototype.reduce, where the initialValue parameter is effectively typed and inferred before the callback, despite the fact that it's on the right. So something like the following might be an issue for the proposal:
function foo<...T>(...rest: ...T): ...T
foo(x => x, 0);

Intuitively, T should be [(x: any) => any, number], but if you rely on the order the candidate are added, it will be [number, (x: any) => any]. This is because type argument inference is left to right generally, but functions subject to contextual typing are deferred to the end.
Both the multiplicity and the order issues I've explained are instances of surfacing the candidate list.

@JsonFreeman why you think it'd be an issue?
It can be implemented by virtually introduce extra generic types for each rest factual argument and infer against function with fixed parameters length.
For example,
function foo<...T>(...rest: T) { ... }
foo(x => x, 0);
// to infer, the following function is used
function foo2<T0, T1>(rest0: T0, rest1: T1) { ... }
foo2(x => x, 0);
// inferred as
foo2<(x: any) => any, number>
// T0 = (x: any) => any
// T1 = number
// T = [T0, T1] = [(x: any) => any, number]

BTW, can we infer x => x to be of type { <T>(x: T): T; }?

@Igorbek I think your suggestion about manufacturing type parameters (at least as intuition, regardless of how it is implemented) is the correct way to do it. You could infer a sequence of types for T, where each element in the sequence has an index and a list of candidates (this is an alternate way of implementing what you mentioned).
However, my point was, I do not think this is what would naturally happen if you just repurposed the inference candidate list as the inferred tuple. It would require explicit mechanics to make the right thing happen.
For your point about { <T>(x: T): T; }, that doesn't generalize well to typing things like x => x.length or x => foo(x) where foo is some function.

A small step out from the battle with type-checker inference rules.
I have a comment/suggestion about the syntax. I think there are two consistent but mutually exclusive options:
1. Formal rest type arguments
If we choose this form:
type F<...Args> = (...args:...Args) => ...Args

then we should use it like
var a:  F // a: () => []
var b:  F<number> // b: (arg: number) => [number]
var c:  F<number, string> // c: (arg1: number, arg2: string) => [number, string]
...

Thus it will be true rest formal types. They should be used only at the last position of the formal type parameter section.
2. Tuple-typed rest arguments
(...args:[string, number]) => boolean    IS EQUIVALENT TO   (s: string, n: number) => boolean

In this case we always have fixed number of slots in formal type parameter section.
function f<T>(...args: T): T {
    return args;
}

we infer that T should be a tuple type if either condition is met:

T is used for rest parameters like (...args: T) => T
T is used in spread composition like [...T] or [number, ...T, string]

Thus, we do not need to use an ellipsis in the formal type parameter section (we can infer it even syntactically without any type checker)
in this case, we can write also
function f<T>(...args: [...T]): [...T] {
    return args;
}

but it is redundant.
Personally, I would like to see the later one implemented in TypeScript. @JsonFreeman, @sandersn?

@Artazor I think it boils down to expressivity, and I don't think the two approaches are necessarily equivalent. The second one includes the ability to spread a rest type parameter inside a tuple type, whereas the first does not seem to.
I think for generic type references, it is just a matter of deciding where and syntactically how to use a rest type parameter. This would need to be decided for all type constructors that take a type sequence (tuples, signatures, generic type references).
For generic signatures, it's more complicated because of type argument inference. What if you had the following:
function callback(s: string, n: number): void { }
declare function foo<...T>(cb: (...cbArgs: T) => void, ...args: T): [...T];

foo(callback, "hello", 0, 1);

What does foo return? My point is just that people expect generics rules to be the same for generic types and generic signatures, but if you make generic types more expressive, type argument inference needs a way to handle it. This may just be a matter of formally identifying the cases that are hard for type argument inference, and requiring the user to pass explicit type arguments in these cases.
In terms of my opinion, I think your option 1 is better. I personally do not see the use of using tuple types as rest parameters. I think a rest parameter should only be allowed to be an array type, or a rest type parameter, because it is supposed to have variable length. I also like the concept of a rest type parameter being an abstract sequence of types, not associated with something that already exists in the type system.
My philosophy on tuples is that they represent a subset of array values where the length is known. Those array values are real runtime entities. I don't like the idea of using them a sort of type system device to represent an abstract sequence of types (for instance the sequence of parameters in a signature). But whether you are allowed to spread a rest type parameter in a tuple is a different story.

I like the tuple proposal because it's more powerful and solves more use cases, it's also very intuitive that I can spread a tuple as a rest parameter because tuples are just arrays and when calling a function with a rest parameter I can spread the array. The type system would then match my understanding of the code better.
@JsonFreeman in your case foo would return [string, number, number] as that would be inferred from ...args, the inferred cb type would be (string, number, number) => void and the passed callback would just ignore the last argument which is very common in both TS and JS.

I don't like the idea of using them a sort of type system device to represent an abstract sequence of types

That's exactly what they are, JS doesn't know about tuples, only TS. For TS a tuple is a sequence of types.

I like tuple-based approach too. Especially if we could have compatible functions signatures like that:
// all are equivalent
(a: A, b: B, c: C) => R;
(a: A, b: B, ...rest: [C]) => R;
(a: A, ...rest: [B, C]) => R;
(...args: [A, B, C]) => R;

// this is more complicated
(a: A, ...rest: T[]) => R;
(...args: [A, ...T]) => R; // no in current syntax

The latter we cannot express with current syntax but could if we had #6229 adopted.
So for me it seems that a proper way is to use tuples and unify tuples to express more. Without more expressive tuples, it'd be hard to have something like [...T, ...T] because T as a tuple have an open length.
@JsonFreeman for your example, @Pajn showed exactly as my understanding of that - there's no any visible problems in inferring these types.

@JsonFreeman I'd better use that syntax
declare function foo<T>(cb: (...cbArgs: T) => void, ...args: T): T;
declare function foo<T>(cb: (...cbArgs: T) => void, ...args: T): [...T]; // same

Hm, probably it may introduce some ambiguity:
declare function foo<T>(...args: T): T;
foo(1); // T is [number] or number[]?

// however, here it'd be more explicit
declare function foo<T>(...args: T[]): T[];
foo(1); // T is number[]

// and here
declare function foo<T>(...args: [...T]): T;
foo(1); // T is [number]

I could get behind the idea of spreading a rest type parameter in a tuple. But I'm not sure I want a rest type parameter to be implicitly interpreted as a tuple. @Pajn's example would still work if rest type parameters are allowed to be spread in all type sequence positions (tuples, parameter lists, type arguments).
@Igorbek You're right about the ambiguity in your first example. Your third example is problematic too though. Given a sequence like number, string, there are 2 possible instantiations of the signature. Namely (arg1: number, arg2: string) => [number, string] as well as (arg1: [number, string]) => [number, string] (adopting the implicit tuple interpretation for the sake of the example).

The other odd thing about the implicit tuple interpretation, is this: say you have a rest type parameter T being instantiated to number, string. Now say you pass those as type arguments, Foo<T>. Is that to be interpreted as Foo<[number, string]> whereas Foo<...T> is Foo<number, string>?

Call me crazy, but I sense some fundamental flaws with the idea of using
tuples. What happens if you try to spread a tuple type across too many
parameters? Like this?
declare function foo<T>(...args: [...T]): void
foo<[number]>(1, 2)

Also, what happens if the type parameters are of the wrong type or used in
unusual, potentially erroneous places?
// 1. unusual place
declare foo<T>(x: T, ...ys: [...T]): void

// 2. bad type
declare foo<T>(...xs: [...T]): void
foo<number>(2)

The first example is directly relevant for Function#apply (and could be an
error), and the second is a non-obvious mistake that will fail to compile,
and non-trivial to detect with Intellisense.
On Sun, Feb 28, 2016, 03:04 Jason Freeman<EMAIL_ADDRESS>wrote:

The other odd thing about the implicit tuple interpretation, is this: say
you have a rest type parameter T being instantiated to number, string.
Now say you pass those as type arguments, Foo. Is that to be
interpreted as Foo<[number, string]> whereas Foo<...T> is Foo<number,
string>?
—
Reply to this email directly or view it on GitHub
https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-189817561
.

@JsonFreeman

Your third example is problematic too though. Given a sequence like number, string, there are 2 possible instantiations of the signature. Namely (arg1: number, arg2: string) => [number, string] as well as (arg1: [number, string]) => [number, string] (adopting the implicit tuple interpretation for the sake of the example).

From my third example that is clear it can only interpret as (...args: [number, string]) => [number, string]:
declare function foo<T>(...args: [...T]): T;
foo(1, "a"); // T is [number, string]
const result: [number, string] = foo<[number, string]>(1, "a");

// however, it is assignable to/from the following signatures:
const f1: (arg1: number, arg2: string) => [number, string] = foo<[number, string]>;
const f2: (arg1: number, ...rest: [string]) => [number, string] = foo<[number, string]>;

The other odd thing about the implicit tuple interpretation, is this: say you have a rest type parameter T being instantiated to number, string.

T cannot instantiated to number, string as it is a true tuple. It must be [number, string].

Now say you pass those as type arguments, Foo<T>. Is that to be interpreted as Foo<[number, string]> whereas Foo<...T> is Foo<number, string>?

True. However, having <...T> seems redundant for this particular use cases we're discussing (catch positioned types for rest arguments). Nevertheless, let's say we have it.

There is an argument for this, as it would be extending the spread operator to the type system. But I'd still rather the tuple version be represented as Foo<[...T]>

There're two cases when we might use that syntax:
// in a signature declaration
declare function foo<[...T]>(...args: [...T]): [...T];
// and when type instantiated, so in the usage
type T = [number, string]
foo<T>();
foo<[...T]>();
// the latter can virtually be replaced as
type _T = [...T]; // which is a type operation that should produce [number, string]
foo<_T>();
// and more
type Extended = [boolean, ...T]; // [boolean, number, string]

So for usage it's nothing more than type operator like |, & or []. But in the declaration that syntax might be interpret as T extends any[] or whatever base type for all tuples is, to indicate that must be a tuple type.

@isiahmeadows

What happens if you try to spread a tuple type across too many
parameters? Like this?

declare function foo<T>(...args: [...T]): void
foo<[number]>(1, 2); // ok, foo<[number]> is of type (...args: [number]) => void
// [1, 2] is being passed in place of args
// is [1, 2] which is [number, number] assignable to [number]? yes, with current rules
// no error

Also, what happens if the type parameters are of the wrong type or used in
unusual, potentially erroneous places?

// 1. unusual place
declare foo<T>(x: T, ...ys: [...T]): void
// 1. [...T] can be interpret as a type constraint "must be a tuple type"
// 2. if we call with type specified
foo<number>(1); // number doesn't meet constraint
foo<[number]>(1, 2); // argument of type 'number' is not assignable to parameter 'x' of type '[number]'
foo<[number]>([1], 2); // ok
// 3. if we call without type, it must be inferred
foo(1); // according to current rules, T would be inferred as '{}[]' - base type of all tuples
        // so, argument of type 'number' is not assignable to parameter 'x' of type '{}[]'
foo([1, 2], 2); // T is inferred as '[number, number]
                // rest arguments of type '[number]' are not assignable to rest parameters 'ys' of type '[number, string]'
foo([1], 2, 3); // T is '[number]',
                // x is of type '[number]',
                // ys is of type '[number]',
                // rest arguments are of type '[number, number]' which is assignable to '[number]',
                // no error

// 2. bad type
declare foo<T>(...xs: [...T]): void
foo<number>(2); // type 'number' doesn't meet constraint

I still do not see the benefit of representing these things as tuples. Furthermore, I think they should be declared as <...T> and not <T>. As I said before, I don't see tuple types as an appropriate device to use for arbitrary length type sequences in the type system. I am still not convinced that this is required for the expressivity that people want.

I'd agree it could be more expressive, but having 'spread' operator in type parameters position will limit us to catch rest arguments once only, same as we can't have rest parameters twice. So given <...T> and <A, B, C>, T will catch them as [A, B, C]. And we wouldn't able to express <...T, ...U> as it would be ambiguous - [A, B, C], [] or [A, B], [C] or ... etc.
Let's say I wanted to express a function with the following behavior:
declare function foo(a: A, b: B): R;
declare function boo(c: C, d: D, e: E): U;

let combined: (a: A, b: B, c: C, d: D, e: E) => [R, U] = combine(foo, boo);

// so the signature could be:

declare function combine<R, U, ???>(
  f1: (...args: [...T1]) => R,
  f2: (...args: [...T2]) => U):
    (...args: [...T1, ...T2]) => [R, U];

// if ??? is '...T1, ...T2'
combine<R, U, A, B, C, D, E> // what will be T1 and T2 ?
combine<R, U, ...[A, B, C], ...[D, E]> // ok ? so we will preserve spread to specific positions. so then
combine<...[R, U], A, ...[B, C, D], E> // will be restricted.
// however, ES6 allows to do it with function arguments
f(1, 2, 3);
f(...[1, 2], 3);
f(...[1], ...[2, 3]);

// if ??? is 'T1 extends TupleBase, T2 extends TupleBase'
// or just '[...T1], [...T2]' as a shortcut for such constraints
combine<R, U, [A, B, C], [D, E]> // pretty explicit, and doesn't occupy spread operator for type arguments

Ok, I see now how you are thinking of it. It sounds like what you're proposing is actually a different feature from what I thought. Instead of adding a new construct for capturing a sequence of type parameters, you just want tuple types to be spreadable because they already represent a sequence of types. That way it is possible to pass multiple tuples of various lengths in a more transparent way.
In javascript, it's more like function foo([...rest]) { } instead of function foo(...rest) { }.
That makes more sense to me now, thanks for explaining. I think that is a reasonable approach.

@JsonFreeman Exactly!

@JsonFreeman Question: why should [1, 2] satisfy [number]? That seems very odd to me. That actually working would be very surprising. It's not at all type safe.
Not that I have anything against tuples being used for variadic types, though (I'm neutral, too be honest).

@isiahmeadows in what way is [1, 2] not substituable for [number]? It's definitely a subtype. It's the same how { x: 1, y: 2 } is a valid { x: number }

Okay. I'll concede partially, but do take into account Function.prototype.apply, which accepts a tuple of arguments.
interface Function<T, U, V> {
    (this: T...args: [...U]): V;
    apply(object: T, args: U): V;
}

If the caller throws a TypeError on too many arguments, then passing too many will result in a runtime error, not a compile error like it should.

Isn't it pretty rare for any JS function to throw TypeError when passed too many arguments? What are some examples?

@isiahmeadows as an abstract example, I understood that the error you are worried about is:
function f(x: number): void {
  // throw if too many arguments
}
f.apply(undefined, [1,2,3]); // runtime error, no compile-time error
f(1,2,3) // compile-time error and runtime error.

Is that correct?

@sandersn, I think that TypeError on too many arguments is something that violates the spirit of the JS, as we usually pass function with less formal arguments than actual ones that will be passed into this function. We simply do not use them. For example Array.prototype.forEach

What about function currying? That's probably much more common, with Ramda
and lodash/fp.
On Mon, Feb 29, 2016, 13:45 Anatoly Ressin<EMAIL_ADDRESS>wrote:

@sandersn https://github.com/sandersn, I think that TypeError on too
many arguments is something that violates the spirit of the JS, as we
usually pass function with less formal arguments than actual ones that will
be passed into this function. We simply do not use them. For example
Array.prototype.forEach
—
Reply to this email directly or view it on GitHub
https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-190327066
.

@isiahmeadows I'd say that currying based on the aruments.length is very unstable and runtime error-prone. Real currying is extra-argument-proof:
var plus = x => y => x + y
console.log(plus(3)(4)) // 7
console.log(plus(3,10)(4,20)) // still 7

When I pass my function with fixed signature as callback to somewhere I think about it in the following way: 'my function expects *at least * those arguments'

What about things like foldl?
const list = [1, 2, 3]
console.log(foldl((a, b) => a + b, 0, list))
console.log(foldl((a, b) => a + b, 0)(list))
console.log(foldl((a, b) => a + b)(0, list))
console.log(foldl((a, b) => a + b)(0)(list))

That's very common in functional programming. And omitting the last
argument is fairly common.
On Mon, Feb 29, 2016, 13:52 Anatoly Ressin<EMAIL_ADDRESS>wrote:

@isiahmeadows https://github.com/isiahmeadows I'd say that currying
based on the aruments.length is very unstable and runtime error-prone.
Real currying is extra-argument-proof:
var plus = x => y => x + y
console.log(plus(3)(4)) // 7
console.log(plus(3,10)(4,20)) // still 7
—
Reply to this email directly or view it on GitHub
https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-190330620
.

If you want to pass that as a callback to, say, map (working over a list
of lists), you'll probably want to curry it.
On Mon, Feb 29, 2016, 13:59 Isiah Meadows<EMAIL_ADDRESS>wrote:

What about things like foldl?
const list = [1, 2, 3]
console.log(foldl((a, b) => a + b, 0, list))
console.log(foldl((a, b) => a + b, 0)(list))
console.log(foldl((a, b) => a + b)(0, list))
console.log(foldl((a, b) => a + b)(0)(list))

That's very common in functional programming. And omitting the last
argument is fairly common.
On Mon, Feb 29, 2016, 13:52 Anatoly Ressin<EMAIL_ADDRESS>wrote:

@isiahmeadows https://github.com/isiahmeadows I'd say that currying
based on the aruments.length is very unstable and runtime error-prone.
Real currying is extra-argument-proof:
var plus = x => y => x + y
console.log(plus(3)(4)) // 7
console.log(plus(3,10)(4,20)) // still 7
—
Reply to this email directly or view it on GitHub
https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-190330620
.

I think it's mostly about that:
type T = [number, string];
var a: T = [1, "a", 2]; // valid

// in this cases tuple types or parameter types cannot be inferred:
f(...a, true); // you could think number,string,boolean were passed, but weren't
const c = [...a, true]; // you could think that is of type [number, string, boolean] but it's not
// according to current rules, the best inferred types might be [number, string, number|string|boolean]

// same manner with variadic kinds, types are constructed properly:
type R = [...T, boolean]; // [number, string, boolean]

That's why I've proposed #6229

The question of whether [1, 2] satisfies [number] is a valid one to ask and debate. But what has it got to do with the spreadable tuples feature?

It's whether a variadic application of tuples should ignore extra arguments
or not. This overloaded function should elaborate more of my concern.
declare function foo(x: number, ...args: string[]): void
declare function foo<T>(...args: [...T]): void
foo<[number]>(1, 2)

// This will always fail
declare function foo(x: number, ...args: string[]): void
declare function foo<T>(x: T): void
foo<number>(1, 2)

On Mon, Feb 29, 2016, 18:47 Jason Freeman<EMAIL_ADDRESS>wrote:

The question of whether [1, 2] satisfies [number] is a valid one to ask
and debate. But what has it got to do with the spreadable tuples feature?
—
Reply to this email directly or view it on GitHub
https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-190453352
.

And this is why, for practical reasons, I would prefer rest parameter-like
variadic types.
On Mon, Feb 29, 2016, 19:00 Isiah Meadows<EMAIL_ADDRESS>wrote:

It's whether a variadic application of tuples should ignore extra
arguments or not. This overloaded function should elaborate more of my
concern.
declare function foo(x: number, ...args: string[]): void

declare function foo<T>(...args: [...T]): void
foo<[number]>(1, 2)

// This will always fail
declare function foo(x: number, ...args: string[]): void
declare function foo<T>(x: T): void
foo<number>(1, 2)

On Mon, Feb 29, 2016, 18:47 Jason Freeman<EMAIL_ADDRESS>wrote:

The question of whether [1, 2] satisfies [number] is a valid one to ask
and debate. But what has it got to do with the spreadable tuples feature?
—
Reply to this email directly or view it on GitHub
https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-190453352
.

@JsonFreeman that's because spread operator for types and arrays/tuples. If spread type operator is allowed in form of "given types A, B and T = [A], so then [...T, B] will construct [A, B]" (which is implicitly proposed) then it would not be aligned with array/tuple spread operator. Given var a: [A] and var b: B, the type of expression [...a, b] cannot be proven as to be of type [A, B]. According to current rules of tuples, it could be proven as to be of type [A, A|B].
Does it makes sense for you? Or I can create comparison table to highlight that mismatching.

@Igorbek I understand what you are saying. It ultimately stems from the fact that the compiler has perfect knowledge of the types it's dealing with, but not perfect knowledge of the values. In particular, in your example, the value a has unknown length, whereas the type [A] has known length. This was one of the reasons I was initially uncomfortable about using tuple types for this purpose. But I am not sure it's a serious problem.
@isiahmeadows I see what you are asking about, but why is the issue any clearer with rest type parameters?

The type safe solution would be more consistent with the rest of the
language if it mimicked the argument syntax.
My point is if you're effectively spreading a rest parameter, you get
exactly the argument types and no more. Curried functions have a return
type dependent on the argument type. So if you apply one too many arguments
to partially apply a curried function, you'll get a completely different
type. Handling rest types like tuples would lead to runtime errors instead,
which are never good.
On Tue, Mar 1, 2016, 06:07 Jason Freeman<EMAIL_ADDRESS>wrote:

@Igorbek https://github.com/Igorbek I understand what you are saying.
It ultimately stems from the fact that the compiler has perfect knowledge
of the types it's dealing with, but not perfect knowledge of the values. In
particular, in your example, the value a has unknown length, whereas the
type [A] has known length. This was one of the reasons I was initially
uncomfortable about using tuple types for this purpose. But I am not sure
it's a serious problem.
@isiahmeadows https://github.com/isiahmeadows I see what you are asking
about, but why is the issue any clearer with rest type parameters?
—
Reply to this email directly or view it on GitHub
https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-190667281
.

@isiahmeadows can you give example code for the currying problem?

I still think that even if you used rest type parameters (which I am all for), you'd have to explicitly decide not to allow excess arguments, but I agree with @isiahmeadows that you probably should.

@sandersn
type FullCurry<T> = ((initial: T, xs: T[]) => T) | ((initial: T) => (xs: T[]) => T)
declare function foldl<T>(func: (acc: T, item: T) => T, initial: T, xs: T[]): T
declare function foldl<T>(func: (acc: T, item: T) => T): FullCurry<T>
declare function foldl<T>(func: (acc: T, item: T) => T, initial: T): (xs: T[]) => T

interface Function<T, R, ...A> {
    apply<U extends T>(inst: U, args: [...A]): R
    apply(inst: T, args: [...A]): R
}

function apply(reducer: (initial: number) => number): (number[]) => number {
    reducer.apply(undefined, [0, []])
}

const func = apply(foldl<number>((x, y) => x + y))

func([1, 2, 3]) // Runtime error

I'll add my variation too. Let's see the example of variadic curry from the proposal:
function curry<...T,...U,V>(f: (...ts: [...T, ...U]) => V, ...as:...T): (...bs:...U) => V {
    return ...b => f(...as, ...b);
}

So then, I started to use it:
function f(a: number, b: string, c: string) { return c.toUpperCase(); }
var a: [number, string] = [1, "boo", 2]; // valid
const cf = curry(f, ...a); // cf is of type string => string
cf("a"); // runtime error

@isiahmeadows Whether they are represented as rest type parameters or as tuple types, it sounds like you object to the ability to spread them in a tuple position.
@Igorbek I think your example is similar in that the problem is not how variadic type sequences are represented. It's the ability to spread them in tuples that leads to problems.

@JsonFreeman It's more that I object to this behavior:
class A {}
class B {}
class C {}

declare function foo(a: A, b: B): C;

// This should not work
let value: [A, B, C]
foo(...value)

Does that clarify?

@isiahmeadows it should work actually

I feel it shouldn't. That's my biggest objection. I don't see much reason why it should.
Question: what would be the inferred return type of ret?
declare function foo(a: A, b: B, c: C, d: D): D
let ret = foo.bind(...[new A(), new B(), new D()])

This is actually pretty important.

That last example definitely seems like it shouldn't work. Essentially you need a mechanism to align sequences of types if function.bind is really going to work properly. You would need something akin to unification, where the types of the arguments to bind are matched against the original function's arguments, and then the remained is in the return type.
That said, it doesn't seem like anything in what's been proposed or discussed can handle that, though it's possible I missed something.

I think the biggest problem is that some sort of tuple pattern matching, where each parameter's type is matched against the spread types, needs to be done with the type parameters (a la LiveScript/CoffeeScript's arguments) to fix that problem. It's probably impossible otherwise. And as for how complicated it is, good luck implementing it. :smile:

@JsonFreeman
Or to be more precise, it'll require non-strict (in the sense of eager vs lazy) type checking to work. I also think that's probably a more useful extension than just variadic types, anyways, since it pretty much opens the door for a lot of other more useful things, like self-recursive types.
// I hate this idiom.
interface NestedArray<T> extends Array<Nested<T>> {}
type Nested<T> = T | NestedArray<T>

// I would much prefer this, but it requires non-strict type checking.
type Nested<T> = T | Nested<T>[]

Thankfully, non-strict type checking should be a purely non-breaking change in that only code that previously failed to check now works.
That's probably the biggest thing blocking Function.prototype.bind's proper typing, other than the fact it'll require a very complex type signature.

That's an interesting connection. I'm not convinced they are related though. The recursive types issue is a consequence of the caching policy for generics, and the representation of type aliases in the compiler. All the information is there, it's just the compiler's design that gets in the way.
For the tuple pattern matching, you can't always know how many arguments are being matched against the tuple. If you spread an array into the arguments of bind, you don't know how many are left in the resulting callback.

@JsonFreeman that being said, do you think that as a step of adoption argument spread operator proposal #6229 needs to be considered first?

@JsonFreeman
And non-strict checking of types would allow enough laziness to make it easier to fix that problem with Function.prototype.bind. With such laziness, you could accomplish that type with the following (which will require a tuple syntax to sequence them, unless multiple rest parameters are okay in a type declaration):
interface Function {
    bind<R, T, ...X, ...Y>(
        this: (this: T, ...args: [...X, ...Y]) => R,
        thisObject: T,
        ...args: [...X]
    ): (this: any, ...rest: [...Y]) => R
}

Why would this require non-strict type checking to infer? You have to deduce the rest type step by step to check against the function. Given the following, here's how it would have to check:
// Values
declare function func(a: number, b: string, c: boolean, d?: symbol): number

let f = func.bind(null, 1, "foo")

// How to infer
bind<R, T, ...X, ...Y>(
    this: (this: T, ...args: [...X, ...Y]) => R,
    thisObject: T,
    ...args: [...X]
): (this: any, ...rest: [...Y]) => R

// Infer first type parameter
bind<number, T, ...X, ...Y>(
    this: (this: T, ...args: [...X, ...Y]) => number,
    thisObject: T,
    ...args: [...X]
): (this: any, ...rest: [...Y]) => number

// Infer second type parameter
bind<number, any, ...X, ...Y>(
    this: (this: any, ...args: [...X, ...Y]) => number,
    thisObject: any,
    ...args: [...X]
): (this: any, ...rest: [...Y]) => number

// Infer first part of rest parameter
bind<number, any, number, ...*X, ...Y>(
    this: (this: any, ...args: [number, ...*X, ...Y]) => number,
    thisObject: any,
    ...args: [number, ...*X]
): (this: any, ...rest: [...Y]) => number

// Infer second part of rest parameter
bind<number, any, number, string, ...*X, ...Y>(
    this: (this: any, ...args: [number, string, ...*X, ...Y]) => number,
    thisObject: any,
    ...args: [number, string, ...*X]
): (this: any, ...rest: [...Y]) => number

// First rest parameter ends: all ones that only uses it are fully spread
bind<number, any, number, string, ...Y>(
    this: (this: any, ...args: [number, string, ...Y]) => number,
    thisObject: any,
    ...args: [number, string]
): (this: any, ...rest: [...Y]) => number

// Infer first part of next rest parameter
bind<number, any, number, string, boolean, ...*Y>(
    this: (this: any, ...args: [number, string, boolean, ...*Y]) => number,
    thisObject: any,
    ...args: [number, string]
): (this: any, ...rest: [boolean, ...*Y]) => number

// Infer second part of next rest parameter
// Note that information about optional parameters are retained.
bind<number, any, number, string, boolean, symbol?, ...*Y>(
    this: (
        this: any,
        ...args: [number, string, boolean, symbol?, ...*Y]
    ) => number,
    thisObject: any,
    ...args: [number, string]
): (this: any, ...rest: [boolean, symbol?, ...*Y]) => number

// Second rest parameter ends: all ones that only uses it are exhausted
bind<number, any, number, string, boolean, symbol?>(
    this: (this: any, ...args: [number, string, boolean, symbol?]) => number,
    thisObject: any,
    ...args: [number, string]
): (this: any, ...rest: [boolean, symbol?]) => number

// All rest parameters that are tuples get converted to multiple regular
parameters
bind<number, any, number, string, boolean, symbol?>(
    this: (
        this: any,
        x0: number,
        x1: string,
        x2: boolean,
        x3?: symbol
    ) => number,
    thisObject: any,
    x0: number,
    x1: string
): (this: any, x0: boolean, x1?: symbol) => number

// And this checks

This is how non-strict type checking works. It infers types as needed, instead of the instant it sees it. You can (and should) combine the two passes, so that wrong types fail. Example:
let f = func.bind(null, 1, Symbol("oops"))

// How to infer
bind<R, T, ...X, ...Y>(
    this: (this: T, ...args: [...X, ...Y]) => R,
    thisObject: T,
    ...args: [...X]
): (this: any, ...rest: [...Y]) => R

// Infer first type parameter
bind<number, T, ...X, ...Y>(
    this: (this: T, ...args: [...X, ...Y]) => number,
    thisObject: T,
    ...args: [...X]
): (this: any, ...rest: [...Y]) => number

// Infer second type parameter
bind<number, any, ...X, ...Y>(
    this: (this: any, ...args: [...X, ...Y]) => number,
    thisObject: any,
    ...args: [...X]
): (this: any, ...rest: [...Y]) => number

// Infer first part of rest parameter
bind<number, any, number, ...*X, ...Y>(
    this: (this: any, ...args: [number, ...*X, ...Y]) => number,
    thisObject: any,
    ...args: [number, ...*X]
): (this: any, ...rest: [...Y]) => number

// Infer second part of rest parameter
bind<number, any, number, string, ...*X, ...Y>(
    this: (this: any, ...args: [number, string, ...*X, ...Y]) => number,
    thisObject: any,
    ...args: [number, symbol /* expected string */, ...*X] // fail!
): (this: any, ...rest: [...Y]) => number

In this case, the expected parameter should be the first one inferred in that round, doing a depth-first iteration. In this case, the first one inferred in that search was a string, and symbols aren't assignable to strings, so this fails with that.

And because of this and trying to type Function.prototype.apply, my opinion on using tuples for applying rest types have changed.
interface Function {
    apply<T, R, ...X>(
        this: (this: T, ...args: [...X]) => R,
        thisArg: T,
        args: [...T]
    ): R
}

Few other notes:

There needs to be a way of spreading arrays and tuples as rest type parameters.

interface Foo extends Function<void, ...string[]> {}

There needs to be two separate types for constructors and callables, with Functions being the union of the two. Callable objects should implement the callable interface, class constructors should implement the constructible interface, and ES5 functions should implement the union of the two.

Function.prototype.bind and friends should check against all overloads for the function. If there's multiple that work, it should return a union of all of them.

Those type parameters in your example are not really the type parameters of the bind signature though. They belong to the Function type. But yes, the idea is that if you could use two rest params, or spread two rest type params in a tuple, you would be able to write this.
In order for the signature of bind to be flexible enough, the boundary between ...X and ...Y needs to be decided on a per call basis. It would need to be inferred. It would be a problem if a signature were to use ...X in isolation though. In this case, the boundary will not have been decided. For example:
interface SomeType<T, R, ...X, ...Y> {
     someMethod(someArgs): [...X]; // No way of knowing how long X is
}

And overloads are quite a problem for the Function type. I don't think you want to take the union type elementwise on each argument, because that would allow mixing and matching of parameters between overloads. Is that what you meant?

@JsonFreeman
TL;DR: Skip to the horizontal line break. I have a new, more practical idea.

Yes, I'm aware they really belong on Function itself.

That kind of problem is why I said non-strict type matching (in the sense of Haskell) is necessary. You can't eagerly resolve the type normally, because that one would require an iterative, lazy search to do. It's possible to determine algorithmically, but you would have to keep track of things that wouldn't normally need tracked in like, C++.

If the two arguments are in isolation (like in your example), the compiler should complain. And that situation can be detected with a type-level dependency analysis of each variadic argument in the interface/whatever. It also isn't trivial, but it can be verified when reading the type declaration itself (actually, shortly after).

Although I'm also thinking it might be a little more feasible to define these kinds of situations on just the method in question. It'll also be much easier and faster to detect those kinds of potential problems you alluded to.
interface Function<R, T, ...A> {
    // Split it up for just this method, since it's being resolved relative to the
    // method itself.
    bind[...A = ...X, ...Y](
        this: (this: T, ...args: [...X, ...Y]) => R,
        thisObject: T,
        ...args: [...X]
    ): (this: any, ...rest: [...Y]) => R
}

There is a potential other problem that will be much harder to work out (and why I think it should be constrained to 2, not n divisions):
declare function foo<...T>[...T = ...A, ...B, ...C](
    a: [...A, ...C],
    b: [...A, ...B],
    c: [...B, ...C]
): any

// This should obviously check, but it's non-trivial to figure that out.
let x = foo<
    boolean, number, // ...A
    string, symbol,  // ...B
    Object, any[]  // ...C
>(
    [true, 1, {}, []],
    [true, 1, "hi", Symbol()],
    ["hi", Symbol(), {}, []]
)

Sorry if I'm getting too deep into CS theory here...

Yes, I think that is the right idea. It is not pretty, but I can't think of any other way to properly type bind, knowing the type arguments of Function. The ultimate thing is that a boundary must be inferred. And I agree that it should be limited to 2 buckets so that you have to infer 1 boundary, instead of some arbitrary number of boundaries, which can blow up combinatorially.
There are likely more issues that we have not thought of.

@JsonFreeman Another issue are things like curry. I've yet to come up with something that can properly type that. And it'll take a while before I can. I'd have to do some serious Haskell-like type hacking to come up with such a process.

Thinking about how think kind of proposal could work with some Bluebird functions.
interface PromiseConstructor {
    // all same type
    all<T>(promises: PromiseLike<T>[]):  Promise<T[]>;
    join<T>(...promises: PromiseLike<T>[]):  Promise<T[]>;
    // varying types
    all<...T>(promises: ...PromiseLike<T>): Promise<...T>;
    join<...T>(...promises: ...PromiseLike<T>): Promise<...T>;
    // this is sketchy...    ^
}

interface Promise<...T> {
    // all same type
    then<U>(onFulfill: (values: T[]) => U): Promise<U>;
    spread<U>(onFulfill: (...values: T[]) => U): Promise<U>;
    // varying types
    then<U>(onFulfill: (values: ...T) => U): Promise<U>;
    spread<U>(onFulfill: (...values: ...T) => U): Promise<U>;
}

Do we have a solution for the join<...T>(...promises: ...PromiseLike<T>): Promise<...T>; above?

@DerFlatulator
See my big comment in PromiseConstructor. I also corrected your Promise interface to be a little closer to my proposal.
interface PromiseConstructor {
    new <T>(callback: (
        resolve:
        (thenableOrResult?: T | PromiseLike<T>) => void,
        reject: (error: any) => void
    ) => void): Promise<T, [T]>;
    new <...T>(callback: (
        resolve:
        (thenableOrResult?: [...T] | PromiseLike<[...T]>) => void,
        reject: (error: any) => void
    ) => void): Promise<[...T], ...T>;

    // all same type
    all<T>(promises: PromiseLike<T>[]):  Promise<T[], ...T[]>;
    join<T>(...promises: PromiseLike<T>[]):  Promise<T[], ...T[]>;

    // varying types
    all<...T>(promises: [...PromiseLike<T>]): Promise<[...T], ...T>;
    join<...T>(...promises: [...PromiseLike<T>]): Promise<[...T], ...T>;

    // all<...T>(promises: [...PromiseLike<T>]): Promise<[...T], ...T> should
    // expand to this:
    //
    // all<T1, T2, /* ... */>(promises: [
    //     PromiseLike<T1>,
    //     PromiseLike<T2>,
    //     /* ... */
    // ]): Promise<[T1, T2, /* ... */], T1, T2, /* ... */>;
    //
    // This should hold for all rest parameters, potentially expanding
    // exponentially like ...Promise<[Set<T>], ...Thenable<T>> which should
    // expand to something like this:
    //
    // Promise<[Set<T1>], Thenable<T1>, Thenable<T2> /* ... */>,
    // Promise<[Set<T2>], Thenable<T1>, Thenable<T2> /* ... */>,
    // // etc...
}

interface Promise<T, ...U> {
    // all same type
    then<V>(onFulfill: (values: T) => V): Promise<[V], V>;
    spread<V>(onFulfill: (...values: T) => V): Promise<[V], V>;

    // all same type, returns tuple
    then<...V>(onFulfill: (values: T) => [...V]): Promise<[...V], ...V>;
    spread<...V>(onFulfill: (...values: T) => [...V]): Promise<[...V], ...V>;

    // varying types
    then<V>(onFulfill: (values: [...U]) => V): Promise<[V], V>;
    spread<V>(onFulfill: (...values: [...U]) => V): Promise<[V], V>;

    // varying types, returns tuple
    then<...V>(onFulfill: (values: [...U]) => [...V]): Promise<[V], ...V>;
    spread<...V>(onFulfill: (...values: [...U]) => [...V]): Promise<[V], ...V>;
}

If [...Foo<T>] expands to [Foo<T1>, Foo<T2>, /*... Foo<TN>*/], then is [...Foo<T,U>] a syntax error or a combinatorial expansion?

@DerFlatulator

If exactly one of T or U is a rest parameter, it expands normally. Assuming T is a rest parameter, then it would be [Foo<T1, U>, Foo<T2, U>, /*... Foo<TN, U>*/].
If both are rest parameters, and can have their length correctly inferred, it should be a combinatorial expansion (well...length of T times length of U).
If neither are rest parameters, it's a syntax error.

Note that I strongly oppose more than 2 rest parameters for practical reasons, and that the rest parameters, if they need split up, should only be split on a per-method basis. Something like this:
interface Function<R, T, ...A> {
    // Split it up for just this method, since it's being resolved relative to the
    // method itself.
    bind[...A = ...X, ...Y](
        this: (this: T, ...args: [...X, ...Y]) => R,
        thisObject: T,
        ...args: [...X]
    ): (this: any, ...rest: [...Y]) => R
}

(If someone can come up with a better syntax, I'm all ears. I don't like it, but I can't come up with anything that doesn't visually conflict.)

@isiahmeadows
With 2., in what order would the expansion be?
[
Foo<T1, U1>, Foo<T2, U1>, /*... Foo<TN,U1>*/,
Foo<T1, U2>, Foo<T2, U2>, /*... Foo<TN,U2>*/,
/* ... */
Foo<T1, UN>, Foo<T2, UN>, /*... Foo<TN,UN>*/
]

Or conversely:
[
Foo<T1, U1>, Foo<T1, U2>, /*... Foo<T1,UN>*/,
Foo<T2, U1>, Foo<T2, U2>, /*... Foo<T2,UN>*/,
/* ... */
Foo<TN, U1>, Foo<TN, U2>, /*... Foo<TN,UN>*/
]

Won't this ambiguity would cause confusion? Perhaps limiting to one dimension would be wise.

@DerFlatulator
I'd expect the second. And I'd doubt it would cause too much confusion, since as long as it's consistently that, people would quickly get used to it. It's also an unusual edge case that would only really be run into in practice by people who know what they're doing, or people who should question the need in the first place.
I'm also looking at it as you're expanding the first, then the second for each part of the first. Like this pseudocode:
for (let TT of T) {
  for (let UU of U) {
    expand(TT, UU);
  }
}

Iterating on some of the ideas above...
interface Function<TReturn, TThis, ...TArgs> {
    bind<
      [...TBound, ...TUnbound] = [...TArgs],
      TNewThis
    >(
        thisObject: TNewThis,
        ...args: [...TBound]
    ): Function<TReturn, TNewThis, ...TUnbound>
}

Here, [...TBound, ...TUnbound] = [...TArgs] is valid because the length of ...TBound is known from the length of args. It also permits changing of TThis's type.
One issue with this approach is that you can only bind this once, for example:
interface IFoo { a: number }
interface IBar extends IFoo { b: boolean }
function f(a: number) { }

let x = f.bind(<IBar>{ a: 1, b: false }, 2); // inferred type: Function<number, IBar>
let y = x.bind(<IFoo>{ a: 1 }) // inferred type: Function<number, IFoo>

The inferred type of y is incorrect, it should be Function<number, IBar>. I'm not sure if this is a concern or not, but solving it would require introducing logic into the <T> syntax.
Option 1
interface Function<TReturn, TThis, ...TArgs> {
    bind<
      [...TBound, ...TUnbound] = [...TArgs],
      TNewThis = TThis is undefined ? TNewThis : TThis
    >(
        thisObject: TNewThis,
        ...args: [...TBound]
    ): Function<TReturn, TNewThis, ...TUnbound>
}

Option 2
interface Function<TReturn, TThis, ...TArgs> {
    bind<
      [...TBound, ...TUnbound] = [...TArgs],
      TThis is undefined,
      TNewThis
    >(
        thisObject: TNewThis,
        ...args: [...TBound]
    ): Function<TReturn, TNewThis, ...TUnbound>

    bind<
      [...TBound, ...TUnbound] = [...TArgs],
      TThis is defined
    >(
        thisObject: any,
        ...args: [...TBound]
    ): Function<TReturn, TThis, ...TUnbound>
}

However that would likely be outside the scope of this proposal.

I don't think we should allow such kind of expansions by using type spread operator. I think about spread operator as a "brackets remover" which is absolutely aligned with array spread operator and object/properties spread operator (stage 2 proposal). Just compare:
let a =        [1, 2];
let b = [0, ...a     , 3];
//      [0, ...[1, 2], 3]
//      [0,     1, 2 , 3]  // removed brackets

let c =               { a: 1, b: "b" };
let d = { e: true, ...c               , f: 3 };
//      { e: true, ...{ a: 1, b: "b" }, f: 3 };
//      { e: true,      a: 1, b: "b"  , f: 3 };

You are suggesting to extend it for constructing new set of types:
<...T> = <A, B, C>
...U<T> = <U<A>, U<B>, U<C>>

It's entirely different operation. If you will, it could be modeled by higher order constructs such as:
<...(from R in T select U<R>)> // linq-like
<...(T[R] -> U<R>)> // ugly

@Igorbek How about using an operator to determine what will be expanded?
interface PromiseConstructor {
    all<
      ...T,
      [...TThen] = ...(PromiseLike<@T> | @T)
    >(
      promises: [...TThen]
    ): Promise<[...T], ...T>;
}

Where ...Foo<@T, U> expands to [Foo<T1,U>, /*...*/, Foo<TN,U>].
...(PromiseLike<@T> | @T) expands to
[PromiseLike<T1>|T1, /*...*/, PromiseLike<TN>|TN]
Some syntax alternatives:

...Foo<&T,U>
(T) Foo<T,U>
(...T => Foo<T,U>)
for (T of ...T) Foo<T,U>

I agree with @Igorbek here. At least at this stage, mapping sequences of types does not seem like a priority, given that we are still trying to solve the more basic problem of variadic type parameters.

I don't have much problem with prohibiting it (at least initially), since behavior for that is pretty uninutitive, and two different people might expect two very different things, even. I do agree with @Igorbek for at least now, since TypeScript first needs to have a higher-order type model (that's mapping a type in a sense). And higher order types are not exactly something you can just bolt on.
So definitely :+1: for prohibiting that, probably for quite a while. Even though it's a nice to have, it's complicated as hell to implement, and would be a complete hack to do, since TypeScript doesn't use a functional, type-safe type system.

Coming in a bit late, but I agree with @Igorbek as well. Reiterating my comment made in #1336 and borrowing ideas from C++ parameter packing having clear 'pack' and 'unpack' operators.
Packing types into a tuple seems consistent with Typescript's usage of the spread operator:
let [x, y, ...rest] = [1, 2, 3, 4, 5] // pack
foo(...params) // unpack
let all = [1, 2, ...other, 5] // unpack

// keep in mind this is already implemented, which kind of similar to mapping types
function map(arr) { ... }
let spreadingmap = [1, 2, ...map(other), 5];

Which makes <...T_values> = [T1, T2, T3, etc...] a lot easier to reason about.
While C++ uses spread operator for packing and ellipsis for unpacking, using spread for both is more consistent with Typescript.
module Promise {
  function all<...T_values>(   // pack into a tuple of types, conceptually identical to rest parameters
      values: [ (<PromiseLike<T*>> ...T_values) ]  // unpack, cast, then repack to tuple
  ): Promise<T_values> // keep it packed since T_values is a tuple of whatever types
}

@isiahmeadows @JsonFreeman what would be the point of all this without mapping?
Also as raised in #1336, how about a variadic Array.flatten?

@jameskeane That was the initial idea, but it doesn't cover the case of a middle rest parameter (which some APIs have):
function foo<...T>(a: Foo, b: Bar, ...rest: [...T, Baz]): Foo;

It also doesn't cover Function.prototype.apply vs Function.prototype.call very well.

As for #1336, it might be similarly implemented via this:
angular.module('app').controller(['$scope', function($scope: ng.IScope) { /*etc...*/ }]);

interface IModule {
  controller(injectable: [...string[], () => any]);
}

I have caught up, and realized I was naively assuming tuple types were strict length; which imo is the most intuitive. So assuming we get strict length tuple types (#6229), what are the issues?
@isiahmeadows In your above example of the middle rest parameter case, is it not solved by having strict length tuples? I'm reading ...rest: [...T, Baz] the same as spread unpacking arr = [...other, 123]. This is the same issue you raised with curry, right?
As for apply and call, are they not covered by intersecting types? (Not that I really see the value in having the types on the Function interface anyways).
// as in
const t: [any, string] & [number, any] = [1, "foo"]

interface Function<R, T, ...A> {
    bind<...Y, ...Z>(
        this: (this: T, ...args: A & [...Y, ...Z]) => R, // tricky bit, luckily intersecting tuples is pretty easy
        thisObject: T,
        ...args: Y
    ): (this: any, ...rest: Z) => R
}

@jameskeane
The current variadic proposal assumes #6229 actually ends up accepted (i.e. tuples are strict by default).
As for func.apply, func.bind, func.call, and _.curry, the only problem is with func.bind, _.curry, and friends, or more generally anything using partial application. You also need to be able to choose which rest parameter to separate, and it can only really be done on a per-method basis.
call and apply are pretty straightforward:
type Callable<R, T, ...A> = (this: T, ...args: [...A]) => R;

interface Function<R, T, ...A> {
    call(this: Callable<R, T, ...A>, thisArg: T, ...args: [...A]): R;
    apply(this: Callable<R, T, ...A>, thisArg: T, args: [...A]): R;
}

bind would be more difficult. The split parameters would have to be matched as-needed, unlike eagerly, as is the case now, until the first split half is fully unpacked. This should be implemented as syntax, so the compiler can tell it apart and correctly discern the type without evaluating anything.
// Function.prototype.bind
type Callable<R, T, ...A> = (this: T, ...args: [...A]) => R;
type Constructible<R, ...A> = new (...args: [...A]) => R;

interface Function<R, T, ...A> {
    // my proposed syntax for splitting a rest parameter
    bind[[...A] = [...X, ...Y]](
        this: Callable<R, T, ...A>
        thisArg: T,
        ...args: [...X]
    ): Callable<R, any, ...Y>;

    bind[[...A] = [...X, ...Y]](
        this: Constructible<R, ...A>
        thisArg: T,
        ...args: [...X]
    ): Constructible<R, ...Y>;

    bind[[...A] = [...X, ...Y]](
        this: Callable<R, T, ...A> & Constructible<R, ...A>
        thisArg: T,
        ...args: [...X]
    ): Callable<R, T, ...Y> & Constructible<R, ...Y>;
}

curry would be extremely difficult, as it has to know that f(1, 2, 3) === f(1, 2)(3) === f(1)(2, 3) === f(1)(2)(3). Not only does there have to be the ability to split a rest parameter into two like in bind, there has to be the ability to perform very primitive pattern matching on a per-method basis.
interface Curried<R, T, ...XS> {
    // none passed
    (): this;

    // all passed
    (this: T, ...args: [...XS]): R;
}

interface CurriedMany<R, T, X, ...YS> extends Curried<R, T, X, ...YS>  {
    // penultimate case, constraint that ...YS contains no parameters
    [[...YS] = []](arg: X): Curried<R, T, X>;

    // otherwise, split rest into ...AS and ...BS, with `A` used as the pivot
    // (basically, default case)
    [[...YS] = [...AS, A, ...BS]](
        ...args: [X, ...AS]
    ): CurriedMany<R, T, A, ...BS>;
}

function curry<R, T>(f: (this: T) => R): (this: T) => R;
function curry<R, T, X>(f: (this: T, arg: X) => R): Curried<R, T, A>;
function curry<R, T, X, ...YS>(
    f: (this: T, arg: X, ...args: [...YS]) => R
): CurriedMany<R, T, X, ...YS>;

I don't believe the additions for curry would make it Turing-complete, but it would be close. I think the primary thing preventing it would be the ability to match specializations of a particular type (which C++, Scala, and Haskell, three languages with Turing-complete type systems, all have).

@sandersn I couldn't see an example above, but can I ask about constraints on variadic parameters?
Consider the following example:
interface HasKey<T> {
    Key(): T;
}

class Row<...T extends HasKey<X>, X> {
    // ...
}

Incidentally, see https://github.com/Microsoft/TypeScript/issues/7848 for discussion on potentially dropping the requirement that X needs to be listed
Now there is potentially some ambiguity here as to whether the constraint is:

(...T) extends HasKey<X> or
...(T extends HasKey<X>)

In this example I'm assuming 2.
Will these sorts of constraints (1 and/or 2) be possible?

@myitcv 2 would probably be the best route to go, but it would make sense to just reuse existing logic for checking the constraint.

Well...I just realized something: how would arrays containing variadic types? Or more specifically, what type is arg below?
function processItems<...T>(...args: [...T]): void {
    for (const arg of args) { // Here
        process(arg);
    }
}

I guess you are asking what is the element type of args. For tuples, I believe this is usually the union type of the elements. I can't think of a better way to type that.
@sandersn can you comment on what is the status of this feature?

@JsonFreeman I was asking specifically what arg was. In my opinion, it should be any for my original example, and Item<T> with below (with the F-bounded T):
function processItems<...T extends Item<T>>(...args: [...T]): void {
    for (const arg of args) { // Here
        process(arg);
    }
}

This is so the types can be resolved locally. You don't know the types beforehand, and this will speed up compilation tremendously, since you don't have to compute the types within the function for each call to it. Note that if you just need the type of a single argument, typeof arg will suffice, and would likely be shorter.

Oh sorry, for the original example, I meant that the type should be T.

I meant Item<any> in the second...Sorry.

When I said it should be T, I was assuming T is a type, but I guess the whole point of this feature is that T is not a type (I think). So yeah, I guess it should be any and Item<any> in your examples.

But more broadly, I am curious how actively the team is considering this feature for after 2.0. I don't have a strong opinion, just wondering.

The reason I don't think it should necessarily be T is because you don't know what T is. Unless, of course, you mean having the variadic T represent either a single type of the variadic type list, or when spread, the list itself, i.e. T is the subtype of all arguments passed to the argument ...T, and [...T] is assignable to T[].
Or, to clarify what I mean in all the unclear jargon, here's what I mean in terms of code:
// To put it into code
function foo<...T>(list: [...T]): void {
    // This is allowed
    let xs: T[] = list

    // This is allowed
    let list2: [...T] = list

    // This is not allowed
    let list1: [...T] = xs

    // This is allowed
    let item: ?T = null

    // This is not allowed, since it's not immediately initialized
    let other: T

    for (let arg of args) {
        // This is allowed
        let alias: T = arg

        // This is allowed
        let other: ?T = arg

        // This is allowed, since `item` is defined upwards as `?T`
        item = arg

        // This is allowed, since you're doing an unsafe cast from `?T` to `T`.
        alias = item as T
    }
}

That would probably make more sense, though, and it would be much more flexible.

It's still on our nice-to-have list, but it's primarily of interest to library authors and has a decent workaround — n overloads — so I'm not actively working on it. If I had to guess, I'd say 2.1 is possible but not likely.
If/when we commit to properly support object rest/spread (#2103) then variadic kinds might be close enough to spread types to justify doing them all at once. (Spread types are a variant of object types that look like { ...T, x: number, ...U, y: string, ...V }.)

Just want to mention that the n overloads workaround doesn't work for classes or interfaces, which is my particular interest in this feature.

@sandersn Would a pull request for "n overloads" be invited for bind, apply and call in functions, using this typing? I think that would be an acceptable temporary compromise for many, and could catch quite a few bugs in the process for some projects.

@isiahmeadows

The reason I don't think it should necessarily be T is because you don't know what T is.

It seemed to me there was agreement that T is a tuple type of the variadic types. In your original example, the type of arg would be the same as the tuple element type (as @JsonFreeman noted, "the union type of the elements"): For now imagine typescript supports using a tuple as a rest type (#5331).
function processItems<...T>(...args: T): void {
  for (const arg of args) { // Here - arg:number|string|boolean
    const other: ??? = arg; // I think the issue is, how to _represent_ this type?
  }
}
processItems(1, 'foo', false); // T is tuple [number, string, boolean]

Separate from this proposal, I think there should be a way to represent the 'element type' of a tuple. That could be another use for spread, i.e as above ...T :: number|string|boolean; that spreading the tuple type results in it's element type.
for (const arg of args) {
  const cst: ...T = arg;
}

// also, even without variadic types...
type Record = [number, string];
function foo(args: Record) {
  for (const arg in args) {
    const cst: ...Record = arg;
  }
}

With this in mind, your other examples:
function foo<...T>(...list: T): void {
  let xs: T[] = [list, list] // array of the variadic tuple type

  // But this is allowed
  let list5: (...T)[] = [...list]

  // This is *not* allowed
  let list2: [...T] = list

  // This is not allowed
  let list1: [...T] = xs

  // This **is** allowed
  // single element tuple, of variadic union
  // i.e. with number|string|boolean
  //      list4 = [1] or list4 = ['foo'] or list4 = [false]
  let list4: [...T] = [list[n]]

  // This **is**  allowed
  let other: T;

  // This is allowed
  let another: ...T;

  for (let arg of args) {
    another = arg; // allowed, if spreading the tuple is the union type

  }
}

Not loosing sight of my original goal, I wanted a strongly typed Promise.all...
declare module Promise {
  function all<...T>(promises: Promise<...T>[]): T; // means promises is an array of promises to the union type, not what I wanted.

  // Then we need something like, which is now very confusing
  function all<...T>(promises: [...Promise<T*>]): T;
}}

@sandersn Now that other requested features are beginning to depend on this, could the priority maybe be bumped up? bind, call etc. typing depends on this, and ES bind syntax if/when it comes out depends on that, so now there's more riding on this than quirky library authors nagging you all the time. :)
Not that this is particularly constructive to add, but I would be sooo happy if these two features made it into 2.1. I know of at least one library (RxJS), where not only would the codebase itself be improved by these features, consuming code would also be significantly less awkward and prone to bugs. It really would be a breakthrough feature for people looking to write advanced, maintainable functional code.

Could this be used to provide a complete type definition for _.extend, whose return type is the intersection of all its parameters?
declare module underscore {
  function extend<A, B, C, D, ...>(a: A, b: B, c: C, d: D, ...): A&B&C&D&...;
}

Not as such. It needs an extension to the proposal that gives detail on a new operator for variadic kinds — probably called &. @kitsonk proposed this operator earlier, in this comment.
Right now this feature is below a couple of other more immediately important things so I haven't looked at this proposal in a while.

I may have missed it as this is a long thread.
Is the following case being considered?
// javascript
add(fileA, fileB, /* and so on */, handleFn) {...}

While not delivering full variadic kinds, #10727 is part of the solution (and is likely to address the challenges we (@dojo) have).

Good to hear! Although it's still not actually variadic kinds. :( For example, this week when I tried to type Object.assign, I got this far:
interface Object {
  // binary version
  assign<T,U>(target: T, source: U): { ...T, ...U };
  // variadic version: bind a variadic kind variable ...T
  // and then spread it using SIX dots
  assign<...T>(...targets: ...T): { ......T };
}

Note that the "six dots" syntax is object spread of a tuple kind variable, which we haven't really discussed above.

@sandersn
With Object.assign in particular, it could be typed this way, and technically capture a subset (albeit a little too inferrably weak), since it mutates its target (you'd have to have a reference point for this):
assign<T>(target: T, ...sources: Partial<T>[]): T;

The glitch with that is that it mutates its target, changing its structural type in place.

@isiahmeadows then inference would fix T to be the type of target without accounting types of sources. You can try it now with non-variadic version:
declare function _assign<T>(target: T, source: Partial<T>): T;
_assign({}, { a: 10 }); // T is {}

As already mentioned, assign uses a spread type #10727 and can be defined this way:
// non variadic
declare const assign: {
  <T>(target: T): T;
  <T, S>(target: T, source: S): {...T, ...S};
  <T, S1, S2>(target: T, source1: S1, source2: S2): {...T, ...S1, ...S2};
};
// variadic
declare function assign<T, [...S]>(target: T, ...sources: [...S]): {...T, ...[...S]};

Note: I'm still insisting on tuple-based syntax [...T] which has much more sense to me.

@sandersn BTW, is any update on when variadic kinds are going to be landed? Is any chance to see it in 2.2?
And, regarding the syntax, do you still accept feedback on syntax or you're all agreed with that?

The syntax and low level semantics have no clear consensus yet.
On Tue, Dec 13, 2016, 13:26 Igor Oleinikov<EMAIL_ADDRESS>wrote:

@sandersn https://github.com/sandersn BTW, is any update on when
variadic kinds are going to be landed? Is any chance to see it in 2.2?
And, regarding the syntax, do you still accept feedback on syntax or
you're all agreed with that?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-266819647,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AERrBIa5fE8PSk-33w3ToFqHD9MCFoRWks5rHuM5gaJpZM4GYYfH
.

Any idea on what the status of this issue is?

so what are the options you’re thinking about? is this on the agenda with the team? it’s the only weak part of the type system i repeatedly run into. i have two use cases. a simple and a complex, but more general one.
simple would be to add a Tuple extends any[] supertype that can only be subtyped by tuple types. As spreads need to be any[] subtypes, this would work:
export interface Plugin {
	(...args: Args): P | Promise<P>
	postcssPlugin: string
	postcssVersion: string
	postcss: P | Promise<P>
}

at the moment, ...args: T[] is only allowed at the end of signatures.
the complex use case would need ...args: Tuple to be legal anywhere inside a signature (which is no problem, as tuples are fixed-length):
/**
 * Takes a function with callback and transforms it into one returning a promise
 * e.g `fs.write: (fd, buffer, offset, length, position, callback: (err, written: number, buffer: Buffer) => void) => void`
 * gets converted to `(fd, buffer, offset, length, position) => Promise<[number, Buffer]>`
 */
function promisify<A extends Tuple, D extends Tuple, E>
    (wrapped: (...args: A, cb: (error: E, ...data: D) => void) => void)
    : ((...args: A) => Promise<Data>) {
  return (...args) => new Promise((resolve, reject) =>
    wrapped(...args, (e, ...data) =>
      e ? reject(e) : resolve(data)))
}

Yeah I only just started with TypeScript yesterday and this already has made it impossible to automatically type my functions (I can still do it manually of course) because of a single decorator I'm using to wrap my functions in (which is the first thing I tried starting with!):
function portable(func) {
    return function(...args): Out {
        if (this === undefined) {
            return func(...args)
        } else {
            return func(this, ...args)
        }
    }
}

Effectively all the decorator does is makes a function be allowed to be called as a method as well so that they can be attached as a method and work identically, as a basic example here's a bad example which patches the Array prototype with a basic version of flatMap:
function _flatMap<T, R>(
    array: T[],
    iteratee: (item: T) => R[]
): R[] {
    let result: R[] = []
    for (const item of array) {
        for (const value of iteratee(item)) {
            result.push(value)
        }
    }
    return result
}

const flatMap = portable(_flatMap)
Array.prototype.flatMap = flatMap

flatMap([1,2,3,4], x => [x, x])
// Is the same as
[1,2,3,4].flatMap(x => [x, x])
// Is the same as
flatMap.apply([1,2,3,4], [x => x**2])
// Is the same as
flatMap.call([1,2,3,4], x => x**2)

Now hopefully it's obvious that the type of flatMap (not _flatMap) is:
function flatMap<T, R>(this: T[], iteratee: (item: T) => R[]): R[]
function flatMap<T, R>(this: undefined, array: T[], iteratee: (item: T) => R[]): R[]

However I have no way to add types to portable because I can't extract the parameters type from _flatMap to then use within the type definition of the decorated function, I imagine with this proposal I could write something like:
// First argument to func is required for portable to even make sense
function portable<T, R, ...Params>(func: (first: T, ...rest: Params) => R) {
    // The arguments of calling with this is undefined should be simply
    // exactly the same as the input function
    function result(this: undefined, first: T, ...rest: Params): R
    // However when this is of the type of the first argument then the type
    // should be that the parameters are simply the type of the remaining
    // arguments
    function result(this: T, ...rest: Params): R
    function result(...args) {
        if (this === undefined) {
            return func(...args)
        } else {
            return func(this, ...args)
        }
    }
    return result
}

I just wanted to share this as it shows my initial experiences with TypeScript and perhaps shows another case of why variadic generics are important.

@sandersn:

it has a decent workaround - n overloads

While technically not incorrect, I feel this doesn't fully reflect the reality here. Yeah, technically the lack of this could not prevent overloads from typing any function mentioned in this thread; and yet, this minor inconvenience has meant none such overload-based solutions have made it into lib.d.ts so far.
And in fact, many in this thread have felt desperate enough on tackling their respective functions to propose even more syntax not originally part of this proposal, including your ......, as well as ...*X, [...T = ...A, ...B, ...C], [...PromiseLike<T>], <[...X, ...Y] = [...A]>, and <PromiseLike<T*>>.
I think this goes to show that we're all trying to tackle problems here, we share a general sense that we need more powerful syntax like this, and are hoping whatever road we pick here will help lead us to resolve those.
Side note: for Ramda's R.path we had generated a typing of thousand-ish lines of overloads, which still missed tuple support (permutations would've exploded way harder still), and just caused compilation on real projects to not terminate anymore. Recently discovered iteration as a seemingly viable alternative there (#12290).
By the way, afaik you had yet to comment on the proposal laid out by @Artazor and @Igorbek. What were your thoughts on that?
I'd like to argue with a basic implementation like that here (plus #6606) we can do just about anything. I'll offer a couple solutions here to illustrate this, but I'm open to further questions.
Let me first go over some places where a ... operator could be implemented:

v ... for
definition (capture)
use (spread)

function
type Fn = (...args: any[]) => {}
type Returns = typeof fn(...MyTuple); (#6606)

array
type-level tuple destructuring. can technically be emulated using index access + spread (see right) + recursion.
type Arr = [Head, ...Tail];

object
type-level object destructuring. not necessary, just use Omit, see #12215.
type Obj = { a: a, ...restObj }; (not necessary, same as Overwrite, see #12215)

generics
define type Foo<...T> to do Foo<1, 2, 3> (captures [1, 2, 3] into T). fun, but don't know what use-case requires this.
define type Bar<A,B,C> to do Bar<...[1,2,3]> (A = 1 etc.). ditto, don't know of use-cases that need this.

unions (bonus)
?
type Union = "a" | "b"; type MyTuple = ...Union; // ["a", "b"] (order unreliable but enables iteration of unions/objects through tuples. anyway, way out of scope here.)

So there's just two type-level ... instances that are immediately relevant; specifically, the two used here:
declare function f<U, T>(head: U, ...tail: T): [U, ...T];

In the context of #6606, another becomes relevant: the ability to unpack a tuple type for function application, e.g. typeof f(...MyTuple). I think these suffice to solve the tougher problems I've heard mention of here. To try to offer some solutions here:
@jameskeane:

I think there should be a way to represent the 'element type' of a tuple

If you'd like to get the union of their elements, see my TupleToUnion.

Promise.all

// helpers: `mapTuple` needs #5453 to define, #6606 to use
type TupleHasIndex<Arr extends any[], I extends number> = ({[K in keyof Arr]: '1' } & Array<'0'>)[I];
type Inc = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // longer version in gist
declare function mapTuple<F extends (v: T) => any, Tpl extends T[], T>(f: F, tpl: Tpl): MapFn<F, Tpl, T>;
type MapFn<
    F extends (v: T) => any,
    Tpl extends T[],
    T,
    // if empty tuple allowed:
    // I extends number = 0,
    // Acc = []
    // otherwise:
    I extends number = 1,
    Acc = [F(Tpl[0])]
> = { 1: MapFn<F, Tpl, T, Inc[I], [...Acc, F(Tpl[I])]>; 0: Acc; }[TupleHasIndex<Tpl, Int>];

declare module Promise {
  function all<Promises extends Promise<any>[]>(promises: Promises): typeof mapTuple(<T>(prom: Promise<T>) => T, Promises);
}

@danvk:

_.extend

@sandersn:

Object.assign

These are both just variadic versions of Ramda's mergeAll. No six dots needed!
@isiahmeadows:

Any idea on what the status of this issue is?
The syntax and low level semantics have no clear consensus yet.

If I understand correctly you mainly worried whether the approach offered by a few of the others would take into account tackling tougher typings such as the curry and bind you'd mentioned. Here's my take on that particular one, following their proposal.
The strategy is a bit similar, cheating around the fact it's tough to say, extract type requirements for params i~j from a function type into a tuple type, by deferring type-check of arguments to the function application.
// helpers in https://gist.github.com/tycho01/be27a32573339ead953a07010ed3b824, too many to include

// poor man's version, using a given return value rather than using `typeof` based on the given argument types:
function curry<Args extends any[], Ret>(fn: (...args: Args) => Ret): Curried<Args, Ret>;
type Curried<
  ArgsAsked,
  Ret,
  ArgsPrevious = [] // if we can't have empty tuple I guess any[] might also destructures to nothing; that might do.
> = <
  ArgsGiven extends any[] = ArgsGiven,
  ArgsAll extends [...ArgsPrevious, ...ArgsGiven]
      = [...ArgsPrevious, ...ArgsGiven]
  >(...args: ArgsGiven) =>
    If<
      TupleHasIndex<ArgsAll, TupleLastIndex<ArgsAsked>>,
      Ret,
      Curried<ArgsAsked, Ret, ArgsAll>
    >;

// robust alternative that takes into account return values dependent on input params, also needs #6606
function curry<F>(fn: F): Curried<F>;
type Curried<
  F extends (...args: ArgsAsked) => any,
  ArgsAsked extends any[] = ArgsAsked,
  ArgsPrevious = []
> = <
  ArgsGiven extends any[] = ArgsGiven,
  ArgsAll extends [...ArgsPrevious, ...ArgsGiven]
      = [...ArgsPrevious, ...ArgsGiven]
  >(...args: ArgsGiven) =>
    If<
      TupleHasIndex<ArgsAll, TupleLastIndex<ArgsAsked>>,
      F(...[...ArgsPrevious, ...ArgsGiven]),　// #6606
      Curried<ArgsAsked, Ret, ArgsAll>
    >;

// bind:
interface Function {
    bind<
        F extends (this: T, ...args: ArgsAsked) => R,
        ArgsAsked extends any[],
        R extends any,
        T,
        Args1 extends any[] // hard to tie to ArgsAsked, but auto-checked below with #6606
    >(
        this: F,
        thisObject: T,
        ...args: Args1
    ): <Args2 extends DifferenceTuples<ArgsAsked, Args1>>(this: any, ...rest: Args2) => R;
    // ^ `R` alt. to calc return type based on input (needs #6606): `F(this: T, ...[...Args1, ...Args2])`
}

Yeah, I used a bunch of helper types -- just trying to make do with what we have (+ imagine what we could do with just a little more). I'm not so much against ......, ...*X, [...T = ...A, ...B, ...C], [...PromiseLike<T>], <[...X, ...Y] = [...A]>, or <PromiseLike<T*>>. But IMO, even just ... helps address a real issue right now, and I'd love to see it addressed.

 This looks very promising to be able to correctly type curry functions.
But for some real-world projects, one could not want to spend much time to type heavily functional programming oriented piece of code.
So, I am wondering, since --strict is enabled by default in tsconfig.json, if there could be a way to disable type-checking for a part of the code (because of laziness or lack of time).

I would also like to make another suggestion, could we have it so the & and | work with a single tuple argument with this syntax:
<...T>(...args:T): ...T&
// is the same as
<t1, t2, t3>(...args:[t1, t2, t3]): t1 & t2 & t3;
// and
<....T>(...args:T): ...T|
// is the same as
<t1, t2, t3>(...args:[t1, t2, t3]): t1 | t2 | t3;

@HyphnKnight's above suggestion this would be very useful for something that I'm doing too.

I want to add a disclaimer that this proposal is not actively being worked on. But I found exactly the "prior art" kind of paper I wanted to read when I first started looking at this problem: http://www.ccs.neu.edu/racket/pubs/esop09-sthf.pdf
I'll leave that here for future reference.

I opened a few PRs (#17884, #17898) experimenting toward this. The tough parts still remain, but syntax passes at least.

Related question on StackOverflow: Explicit last function parameter in TypeScript
.
@sandersn You proposal would cover this case, as far as I can see, is this correct?
More than 2 years since the proposal, should we still remain hopeful?

Hello!
I'm trying to type a generator that takes a variable number of arrays and mixes and matches elements of them to create a new array.
I want to use this generator in a for...of loop, but can't get proper typing of the values.
Code (there may be mistakes since I haven't run it yet, but this is what I'm trying to do):
function* CombineEveryArgumentWithEveryArgument(...args: any[][]) {
	if (args.length < 1) {
		return [];
	}
	var haselements = false;
	for (var arg of args) {
		if (arg && arg.length > 0) {
			haselements;
		}
	}
	if (!haselements) {
		return [];
	}
	var indexes = [];
	for (var i = 0; i < args.length; i++) {
		indexes.push(0);
	}
	while (true) {
		var values = [];
		//One item from every argument.
		for (var i = 0; i < args.length; i++) {
			values.push(args[i][indexes[i]]);
		}
		if (indexes[0] + 1 < args[0].length) {
			yield values;
		}
		else {
			return values;
		}
		//Increment starting from the last, until we get to the first.
		for (var i = args.length; i > 0; --i) {
			if (indexes[i]++ >= args[i].length) {
				indexes[i] = 0;
			}
			else {
				break;
			}
		}
	}
}

Example usage:
for (let [target, child] of
	CombineEveryArgumentWithEveryArgument(targetsarray, childrenarray)) {

I can't figure out any way to get typing for target and child without creating an intermediary variable.
Something like this would be good?
function * generator<...T[]>(...args: T[]): [...T]

@Griffork the correct practice, until this proposal will be implemented,  is to create many overloads for the functions
for example, see the promise.all types
https://github.com/Microsoft/TypeScript/blob/master/lib/lib.es2015.promise.d.ts#L41-L113

I find this syntax very confusing:
function apply<...T,U>(ap: (...args:...T) => U, args: ...T): U {

this feels much more natural to me:
function apply<T, U>(ap: (...args: T) => U, args: T): U {

At runtime a rest parameter is an array, and we can do this currently in TS:
function apply<T, U>(ap: (...args: T[]) => U, args: T[]): U {

So it seems logical to just remove the restriction of args being an array of T and instead enabling the TS compiler to infer a tuple type for T, e.g.
function apply(ap: (...args: [number, number]) => number, args: [number, number]): number {

I saw that there were some concerns raised about tuples and I don't fully understand them all, but I just wanted to weigh in that in the current proposal it is hard to understand when a developer would need to use ... in a type position and tuples are a lot more intuitive.
... still makes sense to me for concatenating two tuple types though, like [...T, ...U].

@felixfbecker
The proposal for
function apply<...T,U>(ap: (...args:...T) => U, args: ...T): U {

Would be that T is a dynamically created tuple type, so if you pass a string and an int into the function, then T is [string, int].
This is particularly interesting if you want to dynamically express a pattern like this:
function PickArguments<T>(a: T[]): [T];
function PickArguments<T, U>(a: T[], b: U[]): [T, U];
function PickArguments<T, U, V>(a: T[], b: U[], c: V[]): [T, U, V]);
//More overloads for increasing numbers of parameters.

//usage:
var [a, b, c] = PickArguments(["first", "second", "third"], [1, 2, 3], [new Date()]);
var d = b + 1; //b and d are numbers.
var e = c.toDateString(); //c is a date (autocompletes and everything), e is a string.

At the moment if you want to write a function that takes a variable number of arguments and type them generically, you have to write an genericised overload for every number of arguments that function could possibly be given. The ...T proposal essentially allows us to get the compiler to automatcially generate the function definitions for us.
Your proposal:
function apply<T, U>(ap: (...args: T) => U, args: T): U {

Forces all parameters to be treated as the same type, and they can not have more specific type checking. E.g. in my example above, all returned values would be of type any.

I also find the extra ... is very hard to read.
Like @felixfbecker idea, I don't see the need to do:
function apply<...T, U>(ap: (...args: ...T) => U, args: ...T): U {...}

The first thing come to mind when reading apply<...T, is that it is a spread operator, but it actually does not do spreading at all.
@Griffork , in your example T would still be [string, int].
That's what @felixfbecker means by "instead enabling the TS compiler to infer a tuple type for T", at least the way I understand it.

@unional
I read it as the spread operator too, I read it as "spread this type every time it's used".
To me, reading this
function apply<T, U>(ap: (...args: T) => U, args: T): U {

I'd expect T to be a something array (e.g. string[]).
And reading this:
function apply<T, U>(ap: (...args: T[]) => U, args: T[]): U {

I'd expect all args to be assignable to the type T (which is one type, such as string).
The point towards the above proposal was to avoid implicitly making generics capable of representing an arbitrary amount of types.
@felixfbecker
Well then what do you type if you actually want that behavior?

I'd expect T to be a something array (e.g. string[]).

A tuple is "something array", it's just an array with a fixed length and specific types for each element, e.g. [string, number] (vs (string | number)[], which is unbound and does not declare what element has what type).

Well then what do you type if you actually want that behavior?

Not sure what behaviour exactly you are referring to, but I assume "force all parameters to be of the same type", which would be accomplished by ...args: T[].

I read it as the spread operator too, I read it as "spread this type every time it's used".

That's why I think it is confusing.
When you do spread, you just do it, you won't declare something that is "spreadable":
const a = { x: 1, y: 2 }
const b = { ...a }

// likewise
function apply<T>(...args: T): [ ...T, string] {
  args.push('abc')
  return args
}

Yeah. If you want to declare that a generic type argument needs to be "spreadable" (which per ES spec means it must be iterable), we already have a way to express that in TypeScript with extends:
function foo<T extends Iterable<any>>(...args: T): [...T, string] {
  args.push('abc')
  return args
}

const bar = foo(1, true)
// bar is [number, boolean, string]

Which, what we are saying has already been proposed: https://github.com/Microsoft/TypeScript/issues/5453#issuecomment-189703556
But the rest is too long to consume in one seating. 🌷

If tuple concatenation is landing, then we can implement church number! Hooray!
type TupleSuc<T extends [...any]> = [...T, T['length']];
type TupleOne = [0];  // empty tuple is illegal, start with one for now to make it simple.
type TupleTwo = TupleSuc<TupleOne>;
type One = TupleOne['length'];
type Two = TupleTwo['length'];

And if recursion of conditional type is working, we can create tuple with desired length:
type Tuple<N extends number, T = TupleOne> = T['length'] extends N ? T : Tuple<N, Suc<T>>;
type TupleTen = Tuple<10>;
type Ten = TupleTen['length'];

I don't presume I've read all of this thread, but if having ...T in generic parameters is confusing,
why not try to mirror the value-level destructuring syntax further, so that using [...T] in a
type-level argument position destructures the type if it's a type-level tuple? This would also require
allowing typing rest params with tuples, which would make the following equivalent at the call site
in TypeScript:
const first = (a: number, b: string) => …;
const second = (...as: [number, string]) => …;

first(12, "hello"); // ok
second(12, "hello"); // also ok

INB4 "but that's type-directed emit" – no. This doesn't change emit whatsoever, the first still has two
distinct arguments emitted, the second will still have one rest argument. The only thing it changes is
that at the call site, TypeScript will check that the parameters of second match, in order, the tuple
[number, string].
Anyway, assuming we admit the [...Type] syntax, then we could write apply as follows:
function apply<
  [...ArgumentsT], // a type-level tuple of arguments
  ResultT
>(
  // the call site of `toApply` function will be used to infer values of `ArgumentsT`
  toApply:   (...arguments: ArgumentsT) => ResultT,
  arguments: ArgumentsT
) :
  ResultT
{
  // …
}

// NB: using my preferred formatting for complex type-level stuff; hope it's readable for you
// this is entirely equivalent to OP's notation version:
function apply<[...T], U>(ap: (...args: T) => U,  args: T): U {
  // …
}

// so at the call site of
const fn = (a: number, b: string, c: RegExp) => …;

// we have `ArgumentsT` equal to [number, string, RegExp]
apply(fn, [12, "hello" /s+/]); // ok, matches `ArgumentsT`
apply(fn, [12, /s+/]); // not ok, doesn't match `ArgumentsT`

The [...Type] syntax would behave entirely as value-level destructuring, allowing for splitting
and joining type-level tuples, as needed:
type SomeType  = [string, number, "constant"];
type OtherType = ["another-constant", number];

type First<[First, ..._]> = FirstT;
type Rest<[_, ...RestT]> = RestT;
type Concat<[...Left], [...Right]> = [...Left, ...Right];
type FirstTwo<[First, Second, ..._]> = [First, Second];

// has type `string`
const aString: First<SomeType> =
  "strrriiing";
// has type `[number, "constant"]
const numberAndConstant: Rest<SomeType> =
  [42, "constant"];
// has type `[string, number, "constant", "another-constant", number]`
const everything: Concat<SomeType, OtherType> =
  ["herpderp", 42, "constant", "another-constant", 1337];
// has type `[string, number]`
const firstTwo: FirstTwo<SomeType> =
  ["striiiing", 42];

An example on how to type the curry function using this:
type Curried<
  [...ArgumentsT]
  ResultT,
  ArgumentT      = First<ArgumentsT>,
  RestArgumentsT = Rest<ArgumentsT>
> =
  // just ye olde recursione, to build nested functions until we run out of arguments
  RestArgumentsT extends []
    ? (argument: ArgumentT) => ResultT
    : (argument: ArgumentT) => Curried<RestArgumentsT, ResultT>;

// NB. with more complex generic types I usually use generic defaults as a sort-of
// of type-level variable assignment; not at all required for this, just nicer to read IMO

function curry<
  [...ArgumentsT],
  ResultT
>(
  function: (...arguments: ArgumentsT) => ResultT
) :
  Curried<ArgumentsT, ResultT>
{
  // do the magic curry thing here
}

// or in the short indecipherable variable name style

function curry<[...T], U>(fn: (...args: T) => U): Curried<T, U>
{
  // …
}

// this should let you do this (using `fn` from before)
const justAddRegex = curry(fn)(123, "hello");

justAddRegex(/s+/); // ok, matches the arguments of `fn`
justAddRegex(123); // not ok, doesn't match the arguments of `fn`

I assume it would also be helpful to be able to say, that some type argument is a type-level tuple
of some kind. The issue then would be how – considering since 2.7 (I think?) tuple assignability takes
into account tuple length – to express the concept of any type-level tuple. But maybe something like
[...] could work? I have no strong opinion, but it would be good if the concept was nameable.
// bikeshed me
type OnlyTuplesWelcome<ArgumentT extends [...]> = ArgumentT;

In that case the above syntax of [...ArgsT] could basically be a shorthand for ArgsT extends [...],
having the usage of type-level destructuring imply a constraint on the type to be a type-level tuple.
Thoughts?

@jaen:

(...ab: [number, string]) => …

Yeah, that looks like #4130. I tried something at #18004, but my approach was a bit hacky (synthetic nodes).
On expressing any tuple I'd seen someone using any[] & { 0: any }, which I guess works until empty tuple type fwiw. I haven't bothered much personally, mostly just settled for any[].

RxJS needs this all over the place. Most critically for Observable.prototype.pipe, for which we currently have many overloads, but I'm always being asked to add "just one more level".

To second @benlesh we use RXJS extensively and need this for pipe functions.

I'm the author of ppipe, which, like the pipe functions in RXJS, needs this. I think I see a pattern here^^

I'm the author of runtypes, and this feature is desperately needed to express  unions and intersections. The only (incomplete) workaround is gargantuan overloads:
https://github.com/pelotom/runtypes/blob/master/src/types/union.ts
🤢

I'd rewritten the types of ramda, which also need this for e.g. pipe, lenses, and currying.
We needed codegen as currying made directly maintaining overloads unmanageable. Our path type spanned over a thousand lines, at which point we found overload type performance had become problematic as well.

Has the problem with inferring and applying rest arguments been resolved?
function example(head: string, ...tail: number[]): number[] {
  return [Number(head), ...tail]
}

function apply<T, U>(fn: (...args: T) => U, args: T): U {
  return fn.apply(null, args)
}

If the type of T in apply(example, [0, 1, 2, 3]) is inferred as [string, number[]], the call to apply would raise an error.
That means the type of T is really
type T = [string, ...number[]]

or
type T =
  {0: string} &
  {[key: Exclude<number, 0>]: number} &
  Methods

A strange beast indeed, but given how ({0: string} & Array<number>)[0] will
currently resolves to string[1] it seems possible to encode without much change
to the type system.
[1] Is this a bug, should it really be string | number ?

@brunolemos there's a reference to variadic types in the latest design meeting
https://github.com/Microsoft/TypeScript/issues/23045
In order make this feature they need to first create more primitive and concepts iteratively, and when there's enough foundations i'm sure they will add it to any milestone

I managed to implement a working bind

I can not do this
type Last<T extends any[]> =
    T extends [infer P] ? P :
    ((...x: T) => any) extends ((x: any, ...xs: infer XS) => any) ? Last<XS> :

@kgtkr for reference see @fightingcat's trick to get the compiler to overlook the recursion.

thanks
type Last<T extends any[]> = {
    0: never,
    1: Head<T>,
    2: Last<Tail<T>>,
}[T extends [] ? 0 : T extends [any] ? 1 : 2];

Hmm, I have a question. I've got a code like this to handle mixins:
export const Mixed = <

    OP = {}, OS = {}, // base props and state
    AP = {}, AS = {}, // mixin A props and state
    BP = {}, BS = {}, // mixin B props and state
        // ...and other autogenerated stuff
>(

    // TODO: Find a way to write that as ...args with generics:
    a?: ComponentClass<AP, AS>,
    b?: ComponentClass<BP, BS>,
        // ...and other autogenerated stuff

) => {

    type P = OP & AP & BP;
    type S = OS & AS & BS;
    const mixins = [a, b];

    return class extends Component<P, S> {
        constructor(props: P) {
            super(props);
            mixins.map(mix => {
                if (mix) {
                    const prevState = this.state;
                    mix.prototype.constructor.call(this);
                    if (prevState instanceof Object && this.state instanceof Object) {
                        this.state = {
                            ...prevState  as object,
                            ...this.state as object,
                        } as any;
                    }
                }
            });
        }
    };
};

I use it like following:
class SomeComponent extends Mixed(MixinRedux, MixinRouter, MixinForm) {
     // do some stuff with mixed state
}

It works as expected - with proper typing, state handling and so on, but is there any way to rewrite in a more short manner without waiting for a variadic kinds? Because I feel a little dumb about this one right now.

With 3.0 it is now possible to do declare rest args as tupple
declare function foo(...args: [number, string, boolean]): void;

But is it possible to get reversely to get tuple type of arguments of the given function?
Something like Arguments<foo> would be nice.

@whitecolor how about this?
type Arguments<T extends (...x: any[]) => any> = T extends (...x: infer A) => any ? A : never;

with TS 3.0 we can do this now
function compose<X extends any[], Y extends any[], Z extends any[]>(
  f: (...args: X) => Y,
  g: (...args: Y) => Z
): (...args: X) => Z {
  return function (...args) {
    const y = f(...args);
    return g(...y);
  };
}

but we have small problem we have to declare functions that return tupples event for single params and also deal with void somehow and we have to declare return type otherwise it is inferred as array :)
https://www.typescriptlang.org/play/index.html#src=

function foo0()%3A void {

}

function bar0()%3A void {

}

function foo1(a%3A string)%3A [string] {
  return [a]%3B
}

function bar1(a%3A string)%3A [string] {
  return [a]%3B
}

function foo2(a1%3A string%2C a2%3A boolean)%3A [string%2C boolean] {
  return [a1%2C a2]%3B
}

function foo21(a1%3A string%2C a2%3A boolean)%3A [string] {
  return [a1]%3B
}

function bar2(a1%3A string%2C a2%3A boolean)%3A [string%2C boolean] {
  return [a1%2C a2]%3B
}

function compose<X extends any[]%2C Y extends any[]%2C Z extends any[]>(
  f%3A (...args%3A X) %3D> Y%2C
  g%3A (...args%3A Y) %3D> Z
)%3A%20(...args%3A%20X)%20%3D%3E%20Z%20%7B%0D%0A%20%20return%20function%20(...args)%20%7B%0D%0A%20%20%20%20const%20y%20%3D%20f(...args)%3B%0D%0A%20%20%20%20return%20g(...y)%3B%0D%0A%20%20%7D%3B%0D%0A%7D%0D%0A%0D%0A%0D%0A%0D%0A%0D%0Aconst%20baz0%20%3D%20compose(%0D%0A%20%20foo0%2C%0D%0A%20%20bar0%0D%0A)%3B%0D%0A%0D%0Aconst%20baz21%20%3D%20compose(%0D%0A%20%20foo21%2C%0D%0A%20%20bar1%0D%0A)%3B%0D%0Aconst%20baz2%20%3D%20compose(%0D%0A%20%20foo2%2C%0D%0A%20%20bar2%0D%0A)%3B%0D%0A%0D%0A%0D%0Aalert(baz2('a'%2C%20false))%0D%0Aalert(baz21('a'%2C%20true))%0D%0Aalert(baz0())

@maciejw
Use conditional types:
function compose<X extends any[], Y extends any, Z extends any>(
  f: (...args: X) => Y,
  g: Y extends any[] ? (...args: Y) => Z : () => Z
): (...args: X) => Z {
	return function (...args) {
		const y = (f as any)(...args);
		return (g as any)(...y);
	} as any;
}

sure, but this is kind of hacky with those as any :) I think it would be cool if type system supported this without hacks

Well, the types in the function body can be multiple things, there's not really much that can be done about it — you could do something like (f as (...args: any[]) => Y) instead but I think that reduces clarity for no real reason

If variadic types comes to fruition, I would be able to generalize some TypeScript code that I wrote for my own project, that let me fully define the shape of my API, and enforce that shape on the types of the corresponding Node server and JavaScript client library for it.
Generalizing that would allow me to do the same for arbitrary APIs in TypeScript, and go further and probably generate Swagger definitions for other language clients too... could be useful for others! Just dreaming aloud though haha

I succeeded in typing Pipe
https://github.com/kgtkr/typepark/blob/master/src/pipe.ts

@kgtkr: That looks great! :)
The Pipe type crashes TS playground for me (though others work fine), I guess it needs the newest TS?
TS also shows some recursion depth errors -- looks like @isiahmeadows opened #26980 for that.

 Params<T[0]>) => ReturnType<Last<T>>. Any iteration beyond that (aside from intermediate param checks) probably becomes more useful with input-dependent return types.