Skip to content

Commit 2b149df

Browse files
committed
More intro and preview cleanup
1 parent 0b4fd18 commit 2b149df

File tree

1 file changed

+35
-37
lines changed

1 file changed

+35
-37
lines changed

pages/Tuple Kinds.md

+35-37
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,23 @@
22

33
## Give Specific Types to Variadic Functions
44

5-
This proposal lets Typescript users type higher-order functions that take a variable number of parameters.
6-
Functions like this include any `concat`, `apply`, `curry`, `compose`/`pipe` and almost any decorator that wraps a function.
7-
Essentially, any higher-order function that could be written in a functional language with fixed arity should be variable arity in TypeScript in order to support the variety of Javascript uses.
8-
With the ES2015 and ES2017 standards, this use will become even easier as programs start using spread arguments and rest parameters for both arrays and objects.
9-
10-
Currently, Typescript does not support the entire ES2015 spec for spread/rest in argument lists precisely because it has no way to type most spread arguments that do not match a rest argument.
11-
And its support for tuples does not capture nearly all the tuple-like patterns in Javascript.
5+
This proposal lets Typescript give types to higher-order functions that take a variable number of parameters.
6+
Functions like this include `concat`, `apply`, `curry`, `compose` and almost any decorator that wraps a function.
7+
In Javascript, these higher-order functions are expected to accept variadic functionsas arguments.
8+
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.
129
This proposal addresses these use cases with a single, very general typing strategy based on higher-order kinds.
1310

14-
## Preview example with `curry` and decorator
11+
## Preview example with `curry`
1512

16-
`curry` for functions with two arguments is simple to write in Typescript:
13+
`curry` for functions with two arguments is simple to write in Javascript and Typescript:
14+
15+
```js
16+
function curry(f, a) {
17+
return b => f(a, b);
18+
}
19+
```
20+
21+
and in Typescript with type annotations:
1722

1823
```ts
1924
function curry<T, U, V>(f: (t: T, u: U) => V, a:T): (b:U) => V {
@@ -39,16 +44,16 @@ function curry<...T,...U,V>(f: (...ts: [...T, ...U]) => V, ...as:...T): (...bs:.
3944

4045
The syntax for variadic tuple types that I use here matches the spread and rest syntax used for values in Javascript.
4146
This is easier to learn but might make it harder to distinguish type annotations from value expressions.
42-
Similarly, the syntax for concatenating looks like tuple construction, even though it's really concatenation of two type lists.
47+
Similarly, the syntax for concatenating looks like tuple construction, even though it's really concatenation of two tuple types.
4348

44-
To address this question, let's look at an example call to `curry`:
49+
Now let's look at an example call to `curry`:
4550

4651
```ts
4752
function f(n: number, m: number, s: string, c: string): [number, number, string, string] {
4853
return [n,m,s,c];
4954
}
5055
let [n,m,s,c] = curry(f, 1, 2)('foo', 'x');
51-
let [n,m,s,c] = curry(f, 1, 2, 'foo')('x');
56+
let [n,m,s,c] = curry(f, 1, 2, 'foo', 'x')();
5257
```
5358

5459
In the first call,
@@ -63,34 +68,12 @@ In the second call,
6368

6469
```
6570
V = [number, number, string, string]
66-
...T = [number, number, string]]
67-
...U = [string]
71+
...T = [number, number, string, string]
72+
...U = []
6873
```
6974

7075
Note that non-rest parameters can be typed as tuple kinds.
71-
Note that concatenations of variadic kinds cannot be used for type inference, such as in `rotate`:
72-
73-
```js
74-
function rotate(l, n) {
75-
let first = l.slice(0, n);
76-
let rest = l.slice(n);
77-
return [...rest, ...first];
78-
}
79-
rotate([true, true, 'none', 12, 'some'], 3); // returns [12, 'some', true, true, 'none']
80-
```
81-
82-
```ts
83-
function rotate(l:[...T, ...U], n: number): [...U, ...T] {
84-
let first: ...T = l.slice(0, n);
85-
let rest: ...U = l.slice(n);
86-
return [...rest, ...first];
87-
}
88-
rotate<...[boolean, boolean, string], ...[string, number]>([true, true, 'none', 12', 'some'], 3);
89-
```
90-
91-
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.
92-
I'm not sure whether this is code that should actually be supported.
93-
Even if it is, a verbose type annotation is a worthwhile price to pay to handle homogenous lists in Typescript's fairly buttoned-down type system.
76+
The examples section contains several examples of this.
9477

9578
The previous examples show tuples used for variadic kinds.
9679
Note that, if JavaScript supported named arguments, then objects could also be expected to be spread into function calls, and Typescript would also need variadic object kinds.
@@ -259,6 +242,21 @@ twoKinds<[string,string],[string,string]>("an", "ambiguous", "call", "to", "twoK
259242
twoKinds<[number],[number]>(1, "unambiguous", 12);
260243
```
261244

245+
Uncheckable dependencies between type arguments and the function body can arise, as in `rotate`:
246+
247+
```ts
248+
function rotate(l:[...T, ...U], n: number): [...U, ...T] {
249+
let first: ...T = l.slice(0, n);
250+
let rest: ...U = l.slice(n);
251+
return [...rest, ...first];
252+
}
253+
rotate<...[boolean, boolean, string], ...[string, number]>([true, true, 'none', 12', 'some'], 3);
254+
```
255+
256+
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.
257+
I'm not sure whether this is code that should actually be supported.
258+
259+
262260
### Extensions of tuple types
263261
264262
Typescript does not allow users to write an empty tuple type.

0 commit comments

Comments
 (0)