@@ -2555,6 +2555,10 @@ namespace ts {
2555
2555
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
2556
2556
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
2557
2557
}
2558
+ if (type.flags & TypeFlags.SpreadTuple) {
2559
+ const typeNodes = map((<SpreadTupleType>type).elements, (tp: Type) => typeToTypeNodeHelper(tp, context));
2560
+ return createTupleTypeNode(typeNodes, (<SpreadTupleType>type).idxIsSpread);
2561
+ }
2558
2562
2559
2563
Debug.fail("Should be unreachable.");
2560
2564
@@ -3324,6 +3328,12 @@ namespace ts {
3324
3328
writeType((<IndexedAccessType>type).indexType, TypeFormatFlags.None);
3325
3329
writePunctuation(writer, SyntaxKind.CloseBracketToken);
3326
3330
}
3331
+ else if (type.flags & TypeFlags.SpreadTuple) {
3332
+ writePunctuation(writer, SyntaxKind.OpenBracketToken);
3333
+ writePunctuation(writer, SyntaxKind.DotDotDotToken);
3334
+ writeTypeList((<SpreadTupleType>type).elements, SyntaxKind.CommaToken, (<SpreadTupleType>type).idxIsSpread);
3335
+ writePunctuation(writer, SyntaxKind.CloseBracketToken);
3336
+ }
3327
3337
else {
3328
3338
// Should never get here
3329
3339
// { ... }
@@ -3336,7 +3346,7 @@ namespace ts {
3336
3346
}
3337
3347
3338
3348
3339
- function writeTypeList(types: Type[], delimiter: SyntaxKind) {
3349
+ function writeTypeList(types: Type[], delimiter: SyntaxKind, idxIsSpread: boolean[] = [] ) {
3340
3350
for (let i = 0; i < types.length; i++) {
3341
3351
if (i > 0) {
3342
3352
if (delimiter !== SyntaxKind.CommaToken) {
@@ -3345,6 +3355,9 @@ namespace ts {
3345
3355
writePunctuation(writer, delimiter);
3346
3356
writeSpace(writer);
3347
3357
}
3358
+ if (idxIsSpread[i]) {
3359
+ writePunctuation(writer, SyntaxKind.DotDotDotToken);
3360
+ }
3348
3361
writeType(types[i], delimiter === SyntaxKind.CommaToken ? TypeFormatFlags.None : TypeFormatFlags.InElementType);
3349
3362
}
3350
3363
}
@@ -7262,11 +7275,67 @@ namespace ts {
7262
7275
function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
7263
7276
const links = getNodeLinks(node);
7264
7277
if (!links.resolvedType) {
7265
- links.resolvedType = createTupleType(map( node.elementTypes, getTypeFromTypeNode) );
7278
+ links.resolvedType = getTypeForTupleNode( node);
7266
7279
}
7267
7280
return links.resolvedType;
7268
7281
}
7269
7282
7283
+ function getSpreadTupleTypes(elements: Type[], idxIsSpread: boolean[]): Type {
7284
+ return createTupleType(flatMap(elements, (tp: Type, i: number) => idxIsSpread[i] ? getTypeSpreadTypes(tp) : tp));
7285
+ }
7286
+
7287
+ function getTypeSpreadTypes(tuple: Type): Type[] {
7288
+ if (isTupleLikeType(tuple)) {
7289
+ return getTupleTypeElementTypes(tuple);
7290
+ }
7291
+ else {
7292
+ // console.error("not a tuple, don't resolve?");
7293
+ return [];
7294
+ }
7295
+ }
7296
+
7297
+ function isGenericTupleType(type: Type): boolean {
7298
+ return type.flags & TypeFlags.TypeVariable ? true :
7299
+ type.flags & TypeFlags.UnionOrIntersection ? forEach((<UnionOrIntersectionType>type).types, isGenericTupleType) :
7300
+ false;
7301
+ }
7302
+
7303
+ function getTypeForTupleNode(node: TupleTypeNode): Type {
7304
+ if (some(node.elementTypes, (n: TypeNode) => n.kind === SyntaxKind.TypeSpread &&
7305
+ isGenericTupleType(getTypeFromTypeNode((n as TypeSpreadTypeNode).type)))) {
7306
+ const elements = map(node.elementTypes, (n: TypeNode) => getTypeFromTypeNode(n.kind === SyntaxKind.TypeSpread ? (n as TypeSpreadTypeNode).type : n));
7307
+ const idxIsSpread = map(node.elementTypes, (n: TypeNode) => n.kind === SyntaxKind.TypeSpread);
7308
+ return createTupleSpreadType(elements, idxIsSpread);
7309
+ }
7310
+ else {
7311
+ return createTupleType(flatMap(node.elementTypes, getTypeFromTupleElement));
7312
+ }
7313
+ }
7314
+
7315
+ function getTupleTypeElementTypes(type: Type): Type[] {
7316
+ Debug.assert(isTupleLikeType(type));
7317
+ const types = [];
7318
+ let idx = 0;
7319
+ let symbol: Symbol;
7320
+ while (symbol = getPropertyOfObjectType(type, idx++ + "" as __String)) {
7321
+ types.push(getTypeOfSymbol(symbol));
7322
+ }
7323
+ return types;
7324
+ }
7325
+
7326
+ function getTypeFromTupleElement(node: TypeNode | TypeSpreadTypeNode): Type | Type[] {
7327
+ if (node.kind === SyntaxKind.TypeSpread) {
7328
+ const links = getNodeLinks(node);
7329
+ if (!links.resolvedType) {
7330
+ links.resolvedType = getTypeFromTypeNode((node as TypeSpreadTypeNode).type);
7331
+ }
7332
+ return getTypeSpreadTypes(links.resolvedType);
7333
+ }
7334
+ else {
7335
+ return getTypeFromTypeNode(node as TypeNode);
7336
+ }
7337
+ }
7338
+
7270
7339
interface TypeSet extends Array<Type> {
7271
7340
containsAny?: boolean;
7272
7341
containsUndefined?: boolean;
@@ -7630,6 +7699,13 @@ namespace ts {
7630
7699
return type;
7631
7700
}
7632
7701
7702
+ function createTupleSpreadType(elements: Type[], idxIsSpread: boolean[]) {
7703
+ const type = <SpreadTupleType>createType(TypeFlags.SpreadTuple);
7704
+ type.elements = elements;
7705
+ type.idxIsSpread = idxIsSpread;
7706
+ return type;
7707
+ }
7708
+
7633
7709
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
7634
7710
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
7635
7711
const propName = indexType.flags & TypeFlags.StringOrNumberLiteral ?
@@ -8366,6 +8442,9 @@ namespace ts {
8366
8442
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
8367
8443
}
8368
8444
}
8445
+ if (type.flags & TypeFlags.SpreadTuple) {
8446
+ return getSpreadTupleTypes(instantiateTypes((<SpreadTupleType>type).elements, mapper), (<SpreadTupleType>type).idxIsSpread);
8447
+ }
8369
8448
return type;
8370
8449
}
8371
8450
@@ -18930,6 +19009,14 @@ namespace ts {
18930
19009
forEach(node.elementTypes, checkSourceElement);
18931
19010
}
18932
19011
19012
+ function checkTypeSpreadTypeNode(node: TypeSpreadTypeNode) {
19013
+ checkSourceElement(node.type);
19014
+ const type = getApparentType(getTypeFromTypeNode(node.type));
19015
+ if (!isArrayLikeType(type)) { // isTupleLikeType
19016
+ grammarErrorOnNode(node, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types);
19017
+ }
19018
+ }
19019
+
18933
19020
function checkUnionOrIntersectionType(node: UnionOrIntersectionTypeNode) {
18934
19021
forEach(node.types, checkSourceElement);
18935
19022
}
@@ -22494,6 +22581,8 @@ namespace ts {
22494
22581
return checkArrayType(<ArrayTypeNode>node);
22495
22582
case SyntaxKind.TupleType:
22496
22583
return checkTupleType(<TupleTypeNode>node);
22584
+ case SyntaxKind.TypeSpread:
22585
+ return checkTypeSpreadTypeNode(<TypeSpreadTypeNode>node);
22497
22586
case SyntaxKind.UnionType:
22498
22587
case SyntaxKind.IntersectionType:
22499
22588
return checkUnionOrIntersectionType(<UnionOrIntersectionTypeNode>node);
0 commit comments