diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 54788c3553..66667fc38f 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -107,6 +107,8 @@ const TSErrors = makeErrorTemplates( InvalidModifiersOrder: "'%0' modifier must precede '%1' modifier.", InvalidTupleMemberLabel: "Tuple members must be labeled with a simple identifier.", + MissingInterfaceName: + "'interface' declarations must be followed by an identifier.", MixedLabeledAndUnlabeledElements: "Tuple members must all have names or all not have names.", NonAbstractClassHasAbstractMethod: @@ -1419,12 +1421,18 @@ export default (superClass: Class): Class => tsParseInterfaceDeclaration( node: N.TsInterfaceDeclaration, ): N.TsInterfaceDeclaration { - node.id = this.parseIdentifier(); - this.checkLVal( - node.id, - "typescript interface declaration", - BIND_TS_INTERFACE, - ); + if (this.match(tt.name)) { + node.id = this.parseIdentifier(); + this.checkLVal( + node.id, + "typescript interface declaration", + BIND_TS_INTERFACE, + ); + } else { + node.id = null; + this.raise(this.state.start, TSErrors.MissingInterfaceName); + } + node.typeParameters = this.tsTryParseTypeParameters(); if (this.eat(tt._extends)) { node.extends = this.tsParseHeritageClause("extends"); @@ -2305,12 +2313,9 @@ export default (superClass: Class): Class => // export default interface allowed in: // https://github.com/Microsoft/TypeScript/pull/16040 if (this.state.value === "interface") { - const result = this.tsParseDeclaration( - this.startNode(), - this.state.value, - true, - ); - + const interfaceNode = this.startNode(); + this.next(); + const result = this.tsParseInterfaceDeclaration(interfaceNode); if (result) return result; } diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index cef0987a68..4cdee9d296 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -1481,7 +1481,7 @@ export type TsImportType = TsTypeBase & { export type TsInterfaceDeclaration = DeclarationBase & { type: "TSInterfaceDeclaration", - id: Identifier, + id: ?Identifier, typeParameters: ?TsTypeParameterDeclaration, // TS uses "heritageClauses", but want this to resemble ClassBase. extends?: $ReadOnlyArray, diff --git a/packages/babel-parser/test/fixtures/typescript/interface/export-default/input.ts b/packages/babel-parser/test/fixtures/typescript/interface/export-default/input.ts new file mode 100644 index 0000000000..b0f7156d39 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/interface/export-default/input.ts @@ -0,0 +1 @@ +export default interface {} diff --git a/packages/babel-parser/test/fixtures/typescript/interface/export-default/output.json b/packages/babel-parser/test/fixtures/typescript/interface/export-default/output.json new file mode 100644 index 0000000000..e608befa9e --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/interface/export-default/output.json @@ -0,0 +1,31 @@ +{ + "type": "File", + "start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}}, + "errors": [ + "SyntaxError: 'interface' declarations must be followed by an identifier. (1:25)" + ], + "program": { + "type": "Program", + "start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ExportDefaultDeclaration", + "start":0,"end":27,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}}, + "exportKind": "value", + "declaration": { + "type": "TSInterfaceDeclaration", + "start":15,"end":27,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":27}}, + "id": null, + "body": { + "type": "TSInterfaceBody", + "start":25,"end":27,"loc":{"start":{"line":1,"column":25},"end":{"line":1,"column":27}}, + "body": [] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file