You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: pages/Tuple Kinds.md
+87-118
Original file line number
Diff line number
Diff line change
@@ -72,51 +72,12 @@ V = [number, number, string, string]
72
72
...U = []
73
73
```
74
74
75
-
Note that non-rest parameters can be typed as tuple kinds.
76
-
The examples section contains several examples of this.
77
-
78
-
The previous examples show tuples used for variadic kinds.
79
-
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.
80
-
Currently [a stage 2 ECMAScript proposal](https://github.com/sebmarkbage/ecmascript-rest-spread) supports object spreading, but only within object destructuring contexts. Here is an example:
81
-
In Javascript:
82
-
83
-
```js
84
-
functionnamedCurry(f, obj1) {
85
-
returnobj2=>f({...obj1, ...obj2});
86
-
}
87
-
functionf({a, b, c, d}) {
88
-
}
89
-
namedCurry(f, {a:12, b:34})({c:56, d:78});
90
-
```
91
-
92
-
And now with types in TypeScript:
93
-
94
-
```ts
95
-
interfaceFirstHalf {
96
-
a:string;
97
-
b:number;
98
-
}
99
-
interfaceSecondHalf {
100
-
c:string;
101
-
d:boolean;
102
-
}
103
-
interfaceTotalextendsFirstHalf, SecondHalf {
104
-
}
105
-
function namedCurry(f:Total=>void, obj1:FirstHalf):SecondHalf=>void {
106
-
returnobj2=>f({...obj1, ...obj2});
107
-
}
108
-
```
109
-
110
-
So, actually this example doesn't need kinds. That's because named parameters don't exist in Ecmascript 2015: the `arguments` array is an array, not an object.
111
-
112
75
## Syntax
113
76
114
77
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.
115
78
Variadic kind variables can be used in a number of syntactic contexts:
116
79
117
-
### Variadic kind variables
118
-
119
-
Variadic kinds can be bound in the usual location for type variable binding, including functions and classes:
80
+
Variadic kinds can be bound in the usual location for type parameter binding, including functions and classes:
120
81
121
82
```ts
122
83
function f<...T,...U>() {}
@@ -132,26 +93,13 @@ function makeTuple<...T>(ts:...T): ...T {
132
93
returnts;
133
94
}
134
95
function f<...T,...U>(ts:...T): [...T,...U] {
135
-
let us: ...U=makeTuple('hello', 'world'); // note that U is constrained to [string,string] here
96
+
// note that U is constrained to [string,string] in this function
97
+
let us: ...U=makeTuple('hello', 'world');
136
98
return [...ts, ...us];
137
99
}
138
100
```
139
101
140
-
Tuples are instances of variadic kinds, so they continue to appear wherever tuple type annotations were previously allowed:
141
-
142
-
```ts
143
-
function f<...T>(ts:...T): [...T,string,string] {
144
-
let us: [string,string] =makeTuple('hello', 'world'); // note the annotation can be inferred here
145
-
return [...ts, ...us];
146
-
}
147
-
148
-
let tuple: [number, string] = [1,'foo'];
149
-
f<[number,string],[string,string]>(tuple);
150
-
```
151
-
152
-
### Variadic kind operations
153
-
154
-
Variadic kind variables, like type variables, are quite opaque and are not present at runtime.
102
+
Variadic kind variables, like type variables, are quite opaque.
155
103
They do have one operation, unlike type variables.
156
104
They can be concatenated with other kinds or with actual tuples.
157
105
The syntax used for this is identical to the tuple-spreading syntax, but in type annotation location:
@@ -161,14 +109,27 @@ let t1: [...T,...U] = [...ts,...uProducer<...U>()];
161
109
let t2: [...T,string,string,...U,number] = [...ts,'foo','bar',...uProducer<...U>(),12];
162
110
```
163
111
112
+
Tuple types are instances of variadic kinds, so they continue to appear wherever type annotations were previously allowed:
113
+
114
+
```ts
115
+
function f<...T>(ts:...T): [...T,string,string] {
116
+
// note the type of `us` could have been inferred here
117
+
let us: [string,string] =makeTuple('hello', 'world');
118
+
return [...ts, ...us];
119
+
}
120
+
121
+
let tuple: [number, string] = [1,'foo'];
122
+
f<[number,string]>(tuple);
123
+
```
124
+
164
125
## Semantics
165
126
166
127
A variadic kind variable represents a tuple type of any length.
167
128
Since it represents a set of types, we use the term 'kind' to refer to it, following its use in type theory.
168
129
Because the set of types it represents is tuples of any length, we qualify 'kind' with 'variadic'.
169
130
170
131
Therefore, declaring a variable of variadic tuple kind allows it to take on any *single* tuple type.
171
-
Like type variables, kind variables can only be declared by functions, which then allows them to be used inside the body of the function:
132
+
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:
172
133
173
134
```ts
174
135
function f<...T>(): ...T {
@@ -182,15 +143,15 @@ Calling a function with arguments typed as a variadic kind will assign a specifi
182
143
f([1,2,"foo"]);
183
144
```
184
145
185
-
Assigns the tuple type `[number,number,string]` to `...T`.
186
-
So in this application of `f`, `let a:...T` is equivalent to`let a:[number,number,string]`.
187
-
However, because the type of `a` is not known when the function is written, the elements of the tuple cannot be referenced.
188
-
Only concatenation will work.
146
+
Assigns the tuple type `...T=[number,number,string]`...T`.
147
+
So in this application of `f`, `let a:...T` is instantiated as`let a:[number,number,string]`.
148
+
However, because the type of `a` is not known when the function is written, the elements of the tuple cannot be referenced in the body of the function.
149
+
Only creating a new tuple from `a` is allowed.
189
150
For example, new elements can be added to the tuple:
190
151
191
152
```ts
192
-
function cons<H,...Tail>(car:H, cdr: ...Tail): [H,...Tail] {
193
-
return [car, ...cdr];
153
+
function cons<H,...Tail>(head:H, tail: ...Tail): [H,...Tail] {
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
-
231
+
I'm not sure whether this is code that should actually be allowed.
259
232
260
-
### Extensions of tuple types
233
+
### Empty tuple types
261
234
262
235
Typescript does not allow users to write an empty tuple type.
263
-
However, this proposal requires variadic kinds to be bound to a empty tuple.
236
+
However, this proposal requires variadic kinds to be bindable to a empty tuple.
264
237
So Typescript will need to support empty tuples, even if only internally.
265
238
266
239
### Semantics on classes and interfaces
267
240
268
241
The semantics are the same on classes and interfaces.
269
242
243
+
TODO: There are probably some class-specific wrinkles in the semantics.
244
+
270
245
## Examples
271
246
272
247
Most of these examples are possible as fixed-argument functions in current Typescript, but with this proposal they can be written as variadic.
248
+
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.
273
249
This follows typical Javascript practise more closely.
274
250
275
-
### cons/concat
251
+
### Return a concatenated type
276
252
277
253
```ts
278
254
function cons<H,...T>(head:H, tail:...T): [H, ...T] {
0 commit comments