typescript: Support definite assignment assertion (#7159)

This commit is contained in:
Andy 2018-02-24 14:26:07 -08:00 committed by Brian Ng
parent 6f6c8dabba
commit 6f3be3a543
23 changed files with 283 additions and 10 deletions

View File

@ -99,10 +99,13 @@ export function ClassProperty(node: Object) {
this.print(node.key, node);
}
if (node.optional) {
// TS
if (node.optional) {
this.token("?");
}
if (node.definite) {
this.token("!");
}
this.print(node.typeAnnotation, node);
if (node.value) {

View File

@ -290,6 +290,7 @@ export function VariableDeclaration(node: Object, parent: Object) {
export function VariableDeclarator(node: Object) {
this.print(node.id, node);
if (node.definite) this.token("!"); // TS
this.print(node.id.typeAnnotation, node);
if (node.init) {
this.space();

View File

@ -3,4 +3,6 @@ class C {
x?;
x: number;
x: number = 1;
x!;
x!: number;
}

View File

@ -3,4 +3,6 @@ class C {
x?;
x: number;
x: number = 1;
x!;
x!: number;
}

View File

@ -0,0 +1 @@
let x!: number;

View File

@ -0,0 +1 @@
let x!: number;

View File

@ -79,6 +79,10 @@ export default function() {
if (path.node.declare) path.remove();
},
VariableDeclarator({ node }) {
if (node.definite) node.definite = null;
},
ClassMethod(path) {
const { node } = path;
@ -154,7 +158,9 @@ export default function() {
if (node.accessibility) node.accessibility = null;
if (node.abstract) node.abstract = null;
if (node.readonly) node.readonly = null;
if (node.optional) node.optional = null;
if (node.definite) node.definite = null;
if (node.typeAnnotation) node.typeAnnotation = null;
},

View File

@ -1,4 +1,5 @@
class C {
public a?: number;
private b: number = 0;
readonly c!: number = 1;
}

View File

@ -1,3 +1,4 @@
class C {
b = 0;
c = 1;
}

View File

@ -836,6 +836,10 @@ defineType("VariableDeclarator", {
id: {
validate: assertNodeType("LVal"),
},
definite: {
optional: true,
validate: assertValueType("boolean"),
},
init: {
optional: true,
validate: assertNodeType("Expression"),

View File

@ -36,6 +36,10 @@ defineType("ClassProperty", {
validate: assertNodeType("Expression"),
optional: true,
},
definite: {
validate: assertValueType("boolean"),
optional: true,
},
typeAnnotation: {
validate: assertNodeType("TypeAnnotation", "TSTypeAnnotation", "Noop"),
optional: true,

View File

@ -1691,6 +1691,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
parseClassProperty(node: N.ClassProperty): N.ClassProperty {
if (!node.optional && this.eat(tt.bang)) {
node.definite = true;
}
const type = this.tsTryParseTypeAnnotation();
if (type) node.typeAnnotation = type;
return super.parseClassProperty(node);
@ -1752,6 +1756,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// `let x: number;`
parseVarHead(decl: N.VariableDeclarator): void {
super.parseVarHead(decl);
if (decl.id.type === "Identifier" && this.eat(tt.bang)) {
decl.definite = true;
}
const type = this.tsTryParseTypeAnnotation();
if (type) {
decl.id.typeAnnotation = type;
@ -1980,7 +1988,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
isClassProperty(): boolean {
return this.match(tt.colon) || super.isClassProperty();
return (
this.match(tt.bang) || this.match(tt.colon) || super.isClassProperty()
);
}
parseMaybeDefault(...args): N.Pattern {

View File

@ -326,6 +326,9 @@ export type VariableDeclarator = NodeBase & {
type: "VariableDeclarator",
id: Pattern,
init: ?Expression,
// TypeScript only:
definite?: true,
};
// Misc
@ -696,6 +699,7 @@ export type ClassProperty = ClassMemberBase & {
// TypeScript only: (TODO: Not in spec)
readonly?: true,
definite?: true,
};
export type ClassPrivateProperty = NodeBase & {

View File

@ -3,4 +3,6 @@ class C {
x?;
x: number;
x: number = 1;
x!;
x!: number;
}

View File

@ -1,28 +1,28 @@
{
"type": "File",
"start": 0,
"end": 60,
"end": 84,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"line": 8,
"column": 1
}
},
"program": {
"type": "Program",
"start": 0,
"end": 60,
"end": 84,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"line": 8,
"column": 1
}
},
@ -31,14 +31,14 @@
{
"type": "ClassDeclaration",
"start": 0,
"end": 60,
"end": 84,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"line": 8,
"column": 1
}
},
@ -63,14 +63,14 @@
"body": {
"type": "ClassBody",
"start": 8,
"end": 60,
"end": 84,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 6,
"line": 8,
"column": 1
}
},
@ -294,6 +294,108 @@
},
"value": 1
}
},
{
"type": "ClassProperty",
"start": 63,
"end": 66,
"loc": {
"start": {
"line": 6,
"column": 4
},
"end": {
"line": 6,
"column": 7
}
},
"static": false,
"key": {
"type": "Identifier",
"start": 63,
"end": 64,
"loc": {
"start": {
"line": 6,
"column": 4
},
"end": {
"line": 6,
"column": 5
},
"identifierName": "x"
},
"name": "x"
},
"computed": false,
"definite": true,
"value": null
},
{
"type": "ClassProperty",
"start": 71,
"end": 82,
"loc": {
"start": {
"line": 7,
"column": 4
},
"end": {
"line": 7,
"column": 15
}
},
"static": false,
"key": {
"type": "Identifier",
"start": 71,
"end": 72,
"loc": {
"start": {
"line": 7,
"column": 4
},
"end": {
"line": 7,
"column": 5
},
"identifierName": "x"
},
"name": "x"
},
"computed": false,
"definite": true,
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 73,
"end": 81,
"loc": {
"start": {
"line": 7,
"column": 6
},
"end": {
"line": 7,
"column": 14
}
},
"typeAnnotation": {
"type": "TSNumberKeyword",
"start": 75,
"end": 81,
"loc": {
"start": {
"line": 7,
"column": 8
},
"end": {
"line": 7,
"column": 14
}
}
}
},
"value": null
}
]
}

View File

@ -0,0 +1,3 @@
class C {
x?!: number;
}

View File

@ -0,0 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (2:4)"
}

View File

@ -0,0 +1,3 @@
{
"throws": "Complex binding patterns require an initialization value (1:6)"
}

View File

@ -0,0 +1 @@
let x!: number;

View File

@ -0,0 +1,116 @@
{
"type": "File",
"start": 0,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 15
}
},
"program": {
"type": "Program",
"start": 0,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 15
}
},
"sourceType": "module",
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 15
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 4,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 14
}
},
"id": {
"type": "Identifier",
"start": 4,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 14
},
"identifierName": "x"
},
"name": "x",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 6,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 14
}
},
"typeAnnotation": {
"type": "TSNumberKeyword",
"start": 8,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 14
}
}
}
}
},
"definite": true,
"init": null
}
],
"kind": "let"
}
],
"directives": []
}
}