Typescript - Tuple elements can be optional (#8720)

This commit is contained in:
Retsam 2018-10-02 12:29:51 -04:00 committed by Brian Ng
parent 3c87401714
commit a5b5ed928d
21 changed files with 584 additions and 1 deletions

View File

@ -241,6 +241,11 @@ export function TSTupleType(node) {
this.token("]"); this.token("]");
} }
export function TSOptionalType(node) {
this.print(node.typeAnnotation, node);
this.token("?");
}
export function TSUnionType(node) { export function TSUnionType(node) {
this.tsPrintUnionOrIntersectionType(node, "|"); this.tsPrintUnionOrIntersectionType(node, "|");
} }

View File

@ -0,0 +1 @@
let x: [];

View File

@ -0,0 +1 @@
let x: [];

View File

@ -0,0 +1 @@
let x: [string, number?, (string | number)?]

View File

@ -0,0 +1 @@
let x: [string, number?, (string | number)?];

View File

@ -0,0 +1 @@
let x: [number, number, number];

View File

@ -0,0 +1 @@
let x: [number, number, number];

View File

@ -503,13 +503,23 @@ export default (superClass: Class<Parser>): Class<Parser> =>
const node: N.TsTupleType = this.startNode(); const node: N.TsTupleType = this.startNode();
node.elementTypes = this.tsParseBracketedList( node.elementTypes = this.tsParseBracketedList(
"TupleElementTypes", "TupleElementTypes",
this.tsParseType.bind(this), this.tsParseTupleElementType.bind(this),
/* bracket */ true, /* bracket */ true,
/* skipFirstToken */ false, /* skipFirstToken */ false,
); );
return this.finishNode(node, "TSTupleType"); return this.finishNode(node, "TSTupleType");
} }
tsParseTupleElementType(): N.TsType {
const type = this.tsParseType();
if (this.eat(tt.question)) {
const optionalTypeNode: N.TsOptionalType = this.startNodeAtNode(type);
optionalTypeNode.typeAnnotation = type;
return this.finishNode(optionalTypeNode, "TSOptionalType");
}
return type;
}
tsParseParenthesizedType(): N.TsParenthesizedType { tsParseParenthesizedType(): N.TsParenthesizedType {
const node = this.startNode(); const node = this.startNode();
this.expect(tt.parenL); this.expect(tt.parenL);

View File

@ -1104,6 +1104,7 @@ export type TsType =
| TsTypeLiteral | TsTypeLiteral
| TsArrayType | TsArrayType
| TsTupleType | TsTupleType
| TsOptionalType
| TsUnionOrIntersectionType | TsUnionOrIntersectionType
| TsConditionalType | TsConditionalType
| TsInferType | TsInferType
@ -1184,6 +1185,11 @@ export type TsTupleType = TsTypeBase & {
elementTypes: $ReadOnlyArray<TsType>, elementTypes: $ReadOnlyArray<TsType>,
}; };
export type TsOptionalType = TsTypeBase & {
type: "TSOptionalType",
typeAnnotation: TsType,
};
export type TsUnionOrIntersectionType = TsUnionType | TsIntersectionType; export type TsUnionOrIntersectionType = TsUnionType | TsIntersectionType;
export type TsUnionOrIntersectionTypeBase = TsTypeBase & { export type TsUnionOrIntersectionTypeBase = TsTypeBase & {

View File

@ -0,0 +1 @@
let x: [];

View File

@ -0,0 +1,117 @@
{
"type": "File",
"start": 0,
"end": 10,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 10
}
},
"program": {
"type": "Program",
"start": 0,
"end": 10,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 10
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 10,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 10
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 9,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 9
}
},
"id": {
"type": "Identifier",
"start": 4,
"end": 9,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 9
},
"identifierName": "x"
},
"name": "x",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 5,
"end": 9,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 9
}
},
"typeAnnotation": {
"type": "TSTupleType",
"start": 7,
"end": 9,
"loc": {
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 9
}
},
"elementTypes": []
}
}
},
"init": null
}
],
"kind": "let"
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
let x: [string, number?, (string | number)?]

View File

@ -0,0 +1,240 @@
{
"type": "File",
"start": 0,
"end": 44,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 44
}
},
"program": {
"type": "Program",
"start": 0,
"end": 44,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 44
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 44,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 44
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 44,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 44
}
},
"id": {
"type": "Identifier",
"start": 4,
"end": 44,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 44
},
"identifierName": "x"
},
"name": "x",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 5,
"end": 44,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 44
}
},
"typeAnnotation": {
"type": "TSTupleType",
"start": 7,
"end": 44,
"loc": {
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 44
}
},
"elementTypes": [
{
"type": "TSStringKeyword",
"start": 8,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 14
}
}
},
{
"type": "TSOptionalType",
"start": 16,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 23
}
},
"typeAnnotation": {
"type": "TSNumberKeyword",
"start": 16,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 22
}
}
}
},
{
"type": "TSOptionalType",
"start": 25,
"end": 43,
"loc": {
"start": {
"line": 1,
"column": 25
},
"end": {
"line": 1,
"column": 43
}
},
"typeAnnotation": {
"type": "TSParenthesizedType",
"start": 25,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 25
},
"end": {
"line": 1,
"column": 42
}
},
"typeAnnotation": {
"type": "TSUnionType",
"start": 26,
"end": 41,
"loc": {
"start": {
"line": 1,
"column": 26
},
"end": {
"line": 1,
"column": 41
}
},
"types": [
{
"type": "TSStringKeyword",
"start": 26,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 26
},
"end": {
"line": 1,
"column": 32
}
}
},
{
"type": "TSNumberKeyword",
"start": 35,
"end": 41,
"loc": {
"start": {
"line": 1,
"column": 35
},
"end": {
"line": 1,
"column": 41
}
}
}
]
}
}
}
]
}
}
},
"init": null
}
],
"kind": "let"
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
let x: [number, number, number];

View File

@ -0,0 +1,163 @@
{
"type": "File",
"start": 0,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 32
}
},
"program": {
"type": "Program",
"start": 0,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 32
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 32
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 31,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 31
}
},
"id": {
"type": "Identifier",
"start": 4,
"end": 31,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 31
},
"identifierName": "x"
},
"name": "x",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 5,
"end": 31,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 31
}
},
"typeAnnotation": {
"type": "TSTupleType",
"start": 7,
"end": 31,
"loc": {
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 31
}
},
"elementTypes": [
{
"type": "TSNumberKeyword",
"start": 8,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 14
}
}
},
{
"type": "TSNumberKeyword",
"start": 16,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 22
}
}
},
{
"type": "TSNumberKeyword",
"start": 24,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 24
},
"end": {
"line": 1,
"column": 30
}
}
}
]
}
}
},
"init": null
}
],
"kind": "let"
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
function foo(...args: [number, string?]) {}

View File

@ -0,0 +1 @@
function foo(...args) {}

View File

@ -825,6 +825,9 @@ export function assertTSArrayType(node: Object, opts?: Object = {}): void {
export function assertTSTupleType(node: Object, opts?: Object = {}): void { export function assertTSTupleType(node: Object, opts?: Object = {}): void {
assert("TSTupleType", node, opts); assert("TSTupleType", node, opts);
} }
export function assertTSOptionalType(node: Object, opts?: Object = {}): void {
assert("TSOptionalType", node, opts);
}
export function assertTSUnionType(node: Object, opts?: Object = {}): void { export function assertTSUnionType(node: Object, opts?: Object = {}): void {
assert("TSUnionType", node, opts); assert("TSUnionType", node, opts);
} }

View File

@ -793,6 +793,11 @@ export function TSTupleType(...args: Array<any>): Object {
} }
export { TSTupleType as tsTupleType }; export { TSTupleType as tsTupleType };
export { TSTupleType as tSTupleType }; export { TSTupleType as tSTupleType };
export function TSOptionalType(...args: Array<any>): Object {
return builder("TSOptionalType", ...args);
}
export { TSOptionalType as tsOptionalType };
export { TSOptionalType as tSOptionalType };
export function TSUnionType(...args: Array<any>): Object { export function TSUnionType(...args: Array<any>): Object {
return builder("TSUnionType", ...args); return builder("TSUnionType", ...args);
} }

View File

@ -213,6 +213,14 @@ defineType("TSTupleType", {
}, },
}); });
defineType("TSOptionalType", {
aliases: ["TSType"],
visitor: ["typeAnnotation"],
fields: {
typeAnnotation: validateType("TSType"),
},
});
const unionOrIntersection = { const unionOrIntersection = {
aliases: ["TSType"], aliases: ["TSType"],
visitor: ["types"], visitor: ["types"],

View File

@ -2672,6 +2672,20 @@ export function isTSTupleType(node: Object, opts?: Object): boolean {
return false; return false;
} }
export function isTSOptionalType(node: Object, opts?: Object): boolean {
if (!node) return false;
const nodeType = node.type;
if (nodeType === "TSOptionalType") {
if (typeof opts === "undefined") {
return true;
} else {
return shallowEqual(node, opts);
}
}
return false;
}
export function isTSUnionType(node: Object, opts?: Object): boolean { export function isTSUnionType(node: Object, opts?: Object): boolean {
if (!node) return false; if (!node) return false;
@ -4149,6 +4163,7 @@ export function isTSType(node: Object, opts?: Object): boolean {
"TSTypeLiteral" === nodeType || "TSTypeLiteral" === nodeType ||
"TSArrayType" === nodeType || "TSArrayType" === nodeType ||
"TSTupleType" === nodeType || "TSTupleType" === nodeType ||
"TSOptionalType" === nodeType ||
"TSUnionType" === nodeType || "TSUnionType" === nodeType ||
"TSIntersectionType" === nodeType || "TSIntersectionType" === nodeType ||
"TSConditionalType" === nodeType || "TSConditionalType" === nodeType ||