@@ -2555,6 +2555,10 @@ namespace ts {
25552555 const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
25562556 return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
25572557 }
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+ }
25582562
25592563 Debug.fail("Should be unreachable.");
25602564
@@ -3324,6 +3328,12 @@ namespace ts {
33243328 writeType((<IndexedAccessType>type).indexType, TypeFormatFlags.None);
33253329 writePunctuation(writer, SyntaxKind.CloseBracketToken);
33263330 }
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+ }
33273337 else {
33283338 // Should never get here
33293339 // { ... }
@@ -3336,7 +3346,7 @@ namespace ts {
33363346 }
33373347
33383348
3339- function writeTypeList(types: Type[], delimiter: SyntaxKind) {
3349+ function writeTypeList(types: Type[], delimiter: SyntaxKind, idxIsSpread: boolean[] = [] ) {
33403350 for (let i = 0; i < types.length; i++) {
33413351 if (i > 0) {
33423352 if (delimiter !== SyntaxKind.CommaToken) {
@@ -3345,6 +3355,9 @@ namespace ts {
33453355 writePunctuation(writer, delimiter);
33463356 writeSpace(writer);
33473357 }
3358+ if (idxIsSpread[i]) {
3359+ writePunctuation(writer, SyntaxKind.DotDotDotToken);
3360+ }
33483361 writeType(types[i], delimiter === SyntaxKind.CommaToken ? TypeFormatFlags.None : TypeFormatFlags.InElementType);
33493362 }
33503363 }
@@ -7262,11 +7275,67 @@ namespace ts {
72627275 function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
72637276 const links = getNodeLinks(node);
72647277 if (!links.resolvedType) {
7265- links.resolvedType = createTupleType(map( node.elementTypes, getTypeFromTypeNode) );
7278+ links.resolvedType = getTypeForTupleNode( node);
72667279 }
72677280 return links.resolvedType;
72687281 }
72697282
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+
72707339 interface TypeSet extends Array<Type> {
72717340 containsAny?: boolean;
72727341 containsUndefined?: boolean;
@@ -7630,6 +7699,13 @@ namespace ts {
76307699 return type;
76317700 }
76327701
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+
76337709 function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
76347710 const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
76357711 const propName = indexType.flags & TypeFlags.StringOrNumberLiteral ?
@@ -8366,6 +8442,9 @@ namespace ts {
83668442 return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
83678443 }
83688444 }
8445+ if (type.flags & TypeFlags.SpreadTuple) {
8446+ return getSpreadTupleTypes(instantiateTypes((<SpreadTupleType>type).elements, mapper), (<SpreadTupleType>type).idxIsSpread);
8447+ }
83698448 return type;
83708449 }
83718450
@@ -18930,6 +19009,14 @@ namespace ts {
1893019009 forEach(node.elementTypes, checkSourceElement);
1893119010 }
1893219011
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+
1893319020 function checkUnionOrIntersectionType(node: UnionOrIntersectionTypeNode) {
1893419021 forEach(node.types, checkSourceElement);
1893519022 }
@@ -22494,6 +22581,8 @@ namespace ts {
2249422581 return checkArrayType(<ArrayTypeNode>node);
2249522582 case SyntaxKind.TupleType:
2249622583 return checkTupleType(<TupleTypeNode>node);
22584+ case SyntaxKind.TypeSpread:
22585+ return checkTypeSpreadTypeNode(<TypeSpreadTypeNode>node);
2249722586 case SyntaxKind.UnionType:
2249822587 case SyntaxKind.IntersectionType:
2249922588 return checkUnionOrIntersectionType(<UnionOrIntersectionTypeNode>node);
0 commit comments