From 08454ece462ed870f3c18e1274091e2cfb761085 Mon Sep 17 00:00:00 2001 From: Retsam Date: Mon, 8 Oct 2018 12:32:31 -0400 Subject: [PATCH] Typescript - Tuples can include rest elements (#8805) --- .../src/generators/typescript.js | 5 + .../fixtures/typescript/tuple-rest/input.js | 1 + .../fixtures/typescript/tuple-rest/output.js | 1 + .../babel-parser/src/plugins/typescript.js | 9 + packages/babel-parser/src/types.js | 6 + .../typescript/types/tuple-rest/input.js | 1 + .../typescript/types/tuple-rest/output.json | 178 ++++++++++++++++++ .../function/tuple-parameter/input.js | 2 +- .../babel-types/src/definitions/typescript.js | 8 + 9 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 packages/babel-generator/test/fixtures/typescript/tuple-rest/input.js create mode 100644 packages/babel-generator/test/fixtures/typescript/tuple-rest/output.js create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-rest/input.js create mode 100644 packages/babel-parser/test/fixtures/typescript/types/tuple-rest/output.json diff --git a/packages/babel-generator/src/generators/typescript.js b/packages/babel-generator/src/generators/typescript.js index 1fabf7c421..33489ebbb2 100644 --- a/packages/babel-generator/src/generators/typescript.js +++ b/packages/babel-generator/src/generators/typescript.js @@ -246,6 +246,11 @@ export function TSOptionalType(node) { this.token("?"); } +export function TSRestType(node) { + this.token("..."); + this.print(node.typeAnnotation, node); +} + export function TSUnionType(node) { this.tsPrintUnionOrIntersectionType(node, "|"); } diff --git a/packages/babel-generator/test/fixtures/typescript/tuple-rest/input.js b/packages/babel-generator/test/fixtures/typescript/tuple-rest/input.js new file mode 100644 index 0000000000..d7719b2cb4 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/tuple-rest/input.js @@ -0,0 +1 @@ +let x: [string, ...number[]] diff --git a/packages/babel-generator/test/fixtures/typescript/tuple-rest/output.js b/packages/babel-generator/test/fixtures/typescript/tuple-rest/output.js new file mode 100644 index 0000000000..52be881f83 --- /dev/null +++ b/packages/babel-generator/test/fixtures/typescript/tuple-rest/output.js @@ -0,0 +1 @@ +let x: [string, ...number[]]; \ No newline at end of file diff --git a/packages/babel-parser/src/plugins/typescript.js b/packages/babel-parser/src/plugins/typescript.js index 57d67bbff4..bd3d88d9ac 100644 --- a/packages/babel-parser/src/plugins/typescript.js +++ b/packages/babel-parser/src/plugins/typescript.js @@ -511,7 +511,16 @@ export default (superClass: Class): Class => } tsParseTupleElementType(): N.TsType { + // parses `...TsType[]` + if (this.match(tt.ellipsis)) { + const restNode: N.TsRestType = this.startNode(); + this.next(); // skips ellipsis + restNode.typeAnnotation = this.tsParseType(); + return this.finishNode(restNode, "TSRestType"); + } + const type = this.tsParseType(); + // parses `TsType?` if (this.eat(tt.question)) { const optionalTypeNode: N.TsOptionalType = this.startNodeAtNode(type); optionalTypeNode.typeAnnotation = type; diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index 51e2435f0a..c16dc8feec 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -1105,6 +1105,7 @@ export type TsType = | TsArrayType | TsTupleType | TsOptionalType + | TsRestType | TsUnionOrIntersectionType | TsConditionalType | TsInferType @@ -1190,6 +1191,11 @@ export type TsOptionalType = TsTypeBase & { typeAnnotation: TsType, }; +export type TsRestType = TsTypeBase & { + type: "TSRestType", + typeAnnotation: TsType, +}; + export type TsUnionOrIntersectionType = TsUnionType | TsIntersectionType; export type TsUnionOrIntersectionTypeBase = TsTypeBase & { diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest/input.js b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest/input.js new file mode 100644 index 0000000000..d7719b2cb4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest/input.js @@ -0,0 +1 @@ +let x: [string, ...number[]] diff --git a/packages/babel-parser/test/fixtures/typescript/types/tuple-rest/output.json b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest/output.json new file mode 100644 index 0000000000..fd5b5999c5 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/types/tuple-rest/output.json @@ -0,0 +1,178 @@ +{ + "type": "File", + "start": 0, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "VariableDeclaration", + "start": 0, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 4, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "id": { + "type": "Identifier", + "start": 4, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 28 + }, + "identifierName": "x" + }, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 5, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "typeAnnotation": { + "type": "TSTupleType", + "start": 7, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "elementTypes": [ + { + "type": "TSStringKeyword", + "start": 8, + "end": 14, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 1, + "column": 14 + } + } + }, + { + "type": "TSRestType", + "start": 16, + "end": 27, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 27 + } + }, + "typeAnnotation": { + "type": "TSArrayType", + "start": 19, + "end": 27, + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 27 + } + }, + "elementType": { + "type": "TSNumberKeyword", + "start": 19, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 25 + } + } + } + } + } + ] + } + } + }, + "init": null + } + ], + "kind": "let" + } + ], + "directives": [] + } +} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/function/tuple-parameter/input.js b/packages/babel-plugin-transform-typescript/test/fixtures/function/tuple-parameter/input.js index 9d8fadb133..954c72a82a 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/function/tuple-parameter/input.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/function/tuple-parameter/input.js @@ -1 +1 @@ -function foo(...args: [number, string?]) {} +function foo(...args: [number, string?, ...number[]]) {} diff --git a/packages/babel-types/src/definitions/typescript.js b/packages/babel-types/src/definitions/typescript.js index ab1d7eb202..2971853575 100644 --- a/packages/babel-types/src/definitions/typescript.js +++ b/packages/babel-types/src/definitions/typescript.js @@ -221,6 +221,14 @@ defineType("TSOptionalType", { }, }); +defineType("TSRestType", { + aliases: ["TSType"], + visitor: ["typeAnnotation"], + fields: { + typeAnnotation: validateType("TSType"), + }, +}); + const unionOrIntersection = { aliases: ["TSType"], visitor: ["types"],