diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 2e7472e216d2..4cf196b9a704 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -680,6 +680,15 @@ export default (superClass: Class): Class => return this.finishNode(node, "TSLiteralType"); } + tsParseThisTypeOrThisTypePredicate(): N.TsThisType | N.TsTypePredicate { + const thisKeyword = this.tsParseThisTypeNode(); + if (this.isContextual("is") && !this.hasPrecedingLineBreak()) { + return this.tsParseThisTypePredicate(thisKeyword); + } else { + return thisKeyword; + } + } + tsParseNonArrayType(): N.TsType { switch (this.state.type) { case tt.name: @@ -715,14 +724,8 @@ export default (superClass: Class): Class => return this.finishNode(node, "TSLiteralType"); } break; - case tt._this: { - const thisKeyword = this.tsParseThisTypeNode(); - if (this.isContextual("is") && !this.hasPrecedingLineBreak()) { - return this.tsParseThisTypePredicate(thisKeyword); - } else { - return thisKeyword; - } - } + case tt._this: + return this.tsParseThisTypeOrThisTypePredicate(); case tt._typeof: return this.tsParseTypeQuery(); case tt._import: @@ -937,6 +940,24 @@ export default (superClass: Class): Class => this.tsParseTypePredicateAsserts.bind(this), ); + if (asserts && this.match(tt._this)) { + // When asserts is false, thisKeyword is handled by tsParseNonArrayType + // : asserts this is type + let thisTypePredicate = this.tsParseThisTypeOrThisTypePredicate(); + // if it turns out to be a `TSThisType`, wrap it with `TSTypePredicate` + // : asserts this + if (thisTypePredicate.type === "TSThisType") { + const node: N.TsTypePredicate = this.startNodeAtNode(t); + node.parameterName = (thisTypePredicate: N.TsThisType); + node.asserts = true; + thisTypePredicate = this.finishNode(node, "TSTypePredicate"); + } else { + (thisTypePredicate: N.TsTypePredicate).asserts = true; + } + t.typeAnnotation = thisTypePredicate; + return this.finishNode(t, "TSTypeAnnotation"); + } + const typePredicateVariable = this.tsIsIdentifier() && this.tsTryParse(this.tsParseTypePredicatePrefix.bind(this)); @@ -947,15 +968,15 @@ export default (superClass: Class): Class => return this.tsParseTypeAnnotation(/* eatColon */ false, t); } + const node: N.TsTypePredicate = this.startNodeAtNode(t); // : asserts foo - const node = this.startNodeAtNode(t); node.parameterName = this.parseIdentifier(); node.asserts = asserts; t.typeAnnotation = this.finishNode(node, "TSTypePredicate"); return this.finishNode(t, "TSTypeAnnotation"); } - // : foo is type + // : asserts foo is type const type = this.tsParseTypeAnnotation(/* eatColon */ false); const node = this.startNodeAtNode(t); node.parameterName = typePredicateVariable; @@ -989,18 +1010,25 @@ export default (superClass: Class): Class => } tsParseTypePredicateAsserts(): boolean { - if (!this.tsIsIdentifier()) { - return false; - } - - const id = this.parseIdentifier(); if ( - id.name !== "asserts" || - this.hasPrecedingLineBreak() || - !this.tsIsIdentifier() + !this.match(tt.name) || + this.state.value !== "asserts" || + this.hasPrecedingLineBreak() ) { return false; } + const containsEsc = this.state.containsEsc; + this.next(); + if (!this.match(tt.name) && !this.match(tt._this)) { + return false; + } + + if (containsEsc) { + this.raise( + this.state.lastTokStart, + "Escape sequence in keyword asserts", + ); + } return true; } diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index 8392a58db0f2..82815b1443d6 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -1227,6 +1227,7 @@ export type TsTypePredicate = TsTypeBase & { type: "TSTypePredicate", parameterName: Identifier | TsThisType, typeAnnotation: TsTypeAnnotation, + asserts?: boolean, }; // `typeof` operator diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/input.ts b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/input.ts new file mode 100644 index 000000000000..cc1a550f07bb --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/input.ts @@ -0,0 +1,4 @@ +class Foo { + isBar(): asserts this is Foo {} + isBaz = (): asserts this is Foo => {} +} diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/options.json b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/options.json new file mode 100644 index 000000000000..efb11900ba6e --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/options.json @@ -0,0 +1,5 @@ +{ + "plugins": [ + "typescript", "classProperties" + ] +} diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/output.json b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/output.json new file mode 100644 index 000000000000..bed7e168b396 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this-with-predicate/output.json @@ -0,0 +1,397 @@ +{ + "type": "File", + "start": 0, + "end": 87, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 87, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 87, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 9 + }, + "identifierName": "Foo" + }, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 10, + "end": 87, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "body": [ + { + "type": "ClassMethod", + "start": 14, + "end": 45, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "static": false, + "key": { + "type": "Identifier", + "start": 14, + "end": 19, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 7 + }, + "identifierName": "isBar" + }, + "name": "isBar" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "returnType": { + "type": "TSTypeAnnotation", + "start": 21, + "end": 42, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 30 + } + }, + "typeAnnotation": { + "type": "TSTypePredicate", + "start": 31, + "end": 42, + "loc": { + "start": { + "line": 2, + "column": 19 + }, + "end": { + "line": 2, + "column": 30 + } + }, + "parameterName": { + "type": "TSThisType", + "start": 31, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 19 + }, + "end": { + "line": 2, + "column": 23 + } + } + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 39, + "end": 42, + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 30 + } + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 39, + "end": 42, + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 30 + } + }, + "typeName": { + "type": "Identifier", + "start": 39, + "end": 42, + "loc": { + "start": { + "line": 2, + "column": 27 + }, + "end": { + "line": 2, + "column": 30 + }, + "identifierName": "Foo" + }, + "name": "Foo" + } + } + }, + "asserts": true + } + }, + "body": { + "type": "BlockStatement", + "start": 43, + "end": 45, + "loc": { + "start": { + "line": 2, + "column": 31 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "body": [], + "directives": [] + } + }, + { + "type": "ClassProperty", + "start": 48, + "end": 85, + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 39 + } + }, + "static": false, + "key": { + "type": "Identifier", + "start": 48, + "end": 53, + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 7 + }, + "identifierName": "isBaz" + }, + "name": "isBaz" + }, + "computed": false, + "value": { + "type": "ArrowFunctionExpression", + "start": 56, + "end": 85, + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 39 + } + }, + "returnType": { + "type": "TSTypeAnnotation", + "start": 58, + "end": 79, + "loc": { + "start": { + "line": 3, + "column": 12 + }, + "end": { + "line": 3, + "column": 33 + } + }, + "typeAnnotation": { + "type": "TSTypePredicate", + "start": 68, + "end": 79, + "loc": { + "start": { + "line": 3, + "column": 22 + }, + "end": { + "line": 3, + "column": 33 + } + }, + "parameterName": { + "type": "TSThisType", + "start": 68, + "end": 72, + "loc": { + "start": { + "line": 3, + "column": 22 + }, + "end": { + "line": 3, + "column": 26 + } + } + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 76, + "end": 79, + "loc": { + "start": { + "line": 3, + "column": 30 + }, + "end": { + "line": 3, + "column": 33 + } + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 76, + "end": 79, + "loc": { + "start": { + "line": 3, + "column": 30 + }, + "end": { + "line": 3, + "column": 33 + } + }, + "typeName": { + "type": "Identifier", + "start": 76, + "end": 79, + "loc": { + "start": { + "line": 3, + "column": 30 + }, + "end": { + "line": 3, + "column": 33 + }, + "identifierName": "Foo" + }, + "name": "Foo" + } + } + }, + "asserts": true + } + }, + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 83, + "end": 85, + "loc": { + "start": { + "line": 3, + "column": 37 + }, + "end": { + "line": 3, + "column": 39 + } + }, + "body": [], + "directives": [] + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this/input.ts b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this/input.ts new file mode 100644 index 000000000000..839483541d5b --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this/input.ts @@ -0,0 +1,3 @@ +class C { + m(): asserts this {}; +} diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this/output.json b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this/output.json new file mode 100644 index 000000000000..e9d5458c1c89 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-this/output.json @@ -0,0 +1,187 @@ +{ + "type": "File", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "C" + }, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 8, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ClassMethod", + "start": 12, + "end": 32, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "static": false, + "key": { + "type": "Identifier", + "start": 12, + "end": 13, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 3 + }, + "identifierName": "m" + }, + "name": "m" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "returnType": { + "type": "TSTypeAnnotation", + "start": 15, + "end": 29, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "typeAnnotation": { + "type": "TSTypePredicate", + "start": 15, + "end": 29, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "parameterName": { + "type": "TSThisType", + "start": 25, + "end": 29, + "loc": { + "start": { + "line": 2, + "column": 15 + }, + "end": { + "line": 2, + "column": 19 + } + } + }, + "asserts": true + } + }, + "body": { + "type": "BlockStatement", + "start": 30, + "end": 32, + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-var-with-predicate/input.ts b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-var-with-predicate/input.ts new file mode 100644 index 000000000000..2b580e64e906 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-var-with-predicate/input.ts @@ -0,0 +1,3 @@ +class C { + assertIsString(value: unknown): asserts value is string {} +} diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-var-with-predicate/output.json b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-var-with-predicate/output.json new file mode 100644 index 000000000000..f63a5e0581c3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-var-with-predicate/output.json @@ -0,0 +1,267 @@ +{ + "type": "File", + "start": 0, + "end": 72, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 72, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 72, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "C" + }, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 8, + "end": 72, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ClassMethod", + "start": 12, + "end": 70, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 60 + } + }, + "static": false, + "key": { + "type": "Identifier", + "start": 12, + "end": 26, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 16 + }, + "identifierName": "assertIsString" + }, + "name": "assertIsString" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 27, + "end": 41, + "loc": { + "start": { + "line": 2, + "column": 17 + }, + "end": { + "line": 2, + "column": 31 + }, + "identifierName": "value" + }, + "name": "value", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 32, + "end": 41, + "loc": { + "start": { + "line": 2, + "column": 22 + }, + "end": { + "line": 2, + "column": 31 + } + }, + "typeAnnotation": { + "type": "TSUnknownKeyword", + "start": 34, + "end": 41, + "loc": { + "start": { + "line": 2, + "column": 24 + }, + "end": { + "line": 2, + "column": 31 + } + } + } + } + } + ], + "returnType": { + "type": "TSTypeAnnotation", + "start": 42, + "end": 67, + "loc": { + "start": { + "line": 2, + "column": 32 + }, + "end": { + "line": 2, + "column": 57 + } + }, + "typeAnnotation": { + "type": "TSTypePredicate", + "start": 42, + "end": 67, + "loc": { + "start": { + "line": 2, + "column": 32 + }, + "end": { + "line": 2, + "column": 57 + } + }, + "parameterName": { + "type": "Identifier", + "start": 52, + "end": 57, + "loc": { + "start": { + "line": 2, + "column": 42 + }, + "end": { + "line": 2, + "column": 47 + }, + "identifierName": "value" + }, + "name": "value" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 61, + "end": 67, + "loc": { + "start": { + "line": 2, + "column": 51 + }, + "end": { + "line": 2, + "column": 57 + } + }, + "typeAnnotation": { + "type": "TSStringKeyword", + "start": 61, + "end": 67, + "loc": { + "start": { + "line": 2, + "column": 51 + }, + "end": { + "line": 2, + "column": 57 + } + } + } + }, + "asserts": true + } + }, + "body": { + "type": "BlockStatement", + "start": 68, + "end": 70, + "loc": { + "start": { + "line": 2, + "column": 58 + }, + "end": { + "line": 2, + "column": 60 + } + }, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-with-predicate/input.ts b/packages/babel-parser/test/fixtures/typescript/assert-predicate/declare-asserts-var-with-predicate/input.ts similarity index 100% rename from packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-with-predicate/input.ts rename to packages/babel-parser/test/fixtures/typescript/assert-predicate/declare-asserts-var-with-predicate/input.ts diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-with-predicate/output.json b/packages/babel-parser/test/fixtures/typescript/assert-predicate/declare-asserts-var-with-predicate/output.json similarity index 100% rename from packages/babel-parser/test/fixtures/typescript/assert-predicate/asserts-with-predicate/output.json rename to packages/babel-parser/test/fixtures/typescript/assert-predicate/declare-asserts-var-with-predicate/output.json diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/invalid-escaped-asserts-keyword/input.ts b/packages/babel-parser/test/fixtures/typescript/assert-predicate/invalid-escaped-asserts-keyword/input.ts new file mode 100644 index 000000000000..a89b5ad6c9fa --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/invalid-escaped-asserts-keyword/input.ts @@ -0,0 +1 @@ +declare function assertIsString(value: unknown): \u{61}sserts value; diff --git a/packages/babel-parser/test/fixtures/typescript/assert-predicate/invalid-escaped-asserts-keyword/output.json b/packages/babel-parser/test/fixtures/typescript/assert-predicate/invalid-escaped-asserts-keyword/output.json new file mode 100644 index 000000000000..90484c4b93a3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/assert-predicate/invalid-escaped-asserts-keyword/output.json @@ -0,0 +1,170 @@ +{ + "type": "File", + "start": 0, + "end": 68, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 68 + } + }, + "errors": [ + "SyntaxError: Escape sequence in keyword asserts (1:49)" + ], + "program": { + "type": "Program", + "start": 0, + "end": 68, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 68 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "TSDeclareFunction", + "start": 0, + "end": 68, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 68 + } + }, + "id": { + "type": "Identifier", + "start": 17, + "end": 31, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 31 + }, + "identifierName": "assertIsString" + }, + "name": "assertIsString" + }, + "generator": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 32, + "end": 46, + "loc": { + "start": { + "line": 1, + "column": 32 + }, + "end": { + "line": 1, + "column": 46 + }, + "identifierName": "value" + }, + "name": "value", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 37, + "end": 46, + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 46 + } + }, + "typeAnnotation": { + "type": "TSUnknownKeyword", + "start": 39, + "end": 46, + "loc": { + "start": { + "line": 1, + "column": 39 + }, + "end": { + "line": 1, + "column": 46 + } + } + } + } + } + ], + "returnType": { + "type": "TSTypeAnnotation", + "start": 47, + "end": 67, + "loc": { + "start": { + "line": 1, + "column": 47 + }, + "end": { + "line": 1, + "column": 67 + } + }, + "typeAnnotation": { + "type": "TSTypePredicate", + "start": 47, + "end": 67, + "loc": { + "start": { + "line": 1, + "column": 47 + }, + "end": { + "line": 1, + "column": 67 + } + }, + "parameterName": { + "type": "Identifier", + "start": 62, + "end": 67, + "loc": { + "start": { + "line": 1, + "column": 62 + }, + "end": { + "line": 1, + "column": 67 + }, + "identifierName": "value" + }, + "name": "value" + }, + "asserts": true + } + }, + "declare": true + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-types/src/definitions/typescript.js b/packages/babel-types/src/definitions/typescript.js index bba8a5b73c8e..608ea8ab2207 100644 --- a/packages/babel-types/src/definitions/typescript.js +++ b/packages/babel-types/src/definitions/typescript.js @@ -175,11 +175,12 @@ defineType("TSTypeReference", { defineType("TSTypePredicate", { aliases: ["TSType"], - visitor: ["parameterName", "typeAnnotation", "asserts"], + visitor: ["parameterName", "typeAnnotation"], + builder: ["parameterName", "typeAnnotation", "asserts"], fields: { parameterName: validateType(["Identifier", "TSThisType"]), typeAnnotation: validateOptionalType("TSTypeAnnotation"), - asserts: validate(bool), + asserts: validateOptional(bool), }, });