Add import type and export type support to TypeScript (#11171)

* Add support for type only imports in TS (#11053)
* Implement "export type {}" (#11122)
* Add "exportKind: type" when needed with TS (#11157)
* Add `onlyRemoveTypeImports` option to `transform-typescript` (#11173)
* Add onlyRemoveTypeImports to preset-typescript (#11179)

Co-authored-by: Brian Ng <bng412@gmail.com>
Co-authored-by: Raja Sekar <rajasekarm.dev@gmail.com>
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
Co-authored-by: Kai Cataldo <kai@kaicataldo.com>
Co-authored-by: Huáng Jùnliàng <jlhwung@gmail.com>
Co-authored-by: Henry Zhu <smiley.we@gmail.com>
Co-authored-by: Siddhant N Trivedi <sidntrivedi012@gmail.com>
This commit is contained in:
Nicolò Ribaudo 2020-03-16 22:58:51 +01:00 committed by GitHub
parent 20d9a10186
commit 740260b236
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 1799 additions and 44 deletions

View File

@ -0,0 +1,2 @@
export interface A {}
export type B = string;

View File

@ -0,0 +1,2 @@
export interface A {}
export type B = string;

View File

@ -0,0 +1,3 @@
type A = 2;
export type { A };
export type { B } from "./mod";

View File

@ -0,0 +1,3 @@
type A = 2;
export type { A };
export type { B } from "./mod";

View File

@ -0,0 +1,3 @@
import type T from './mod';
import type { A, B } from './mod';
import type * as Types from './mod';

View File

@ -0,0 +1,3 @@
import type T from './mod';
import type { A, B } from './mod';
import type * as Types from './mod';

View File

@ -1865,7 +1865,30 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (this.match(tt.name) && this.lookahead().type === tt.eq) { if (this.match(tt.name) && this.lookahead().type === tt.eq) {
return this.tsParseImportEqualsDeclaration(node); return this.tsParseImportEqualsDeclaration(node);
} }
return super.parseImport(node);
if (this.eatContextual("type")) {
node.importKind = "type";
} else {
node.importKind = "value";
}
const importNode = super.parseImport(node);
/*:: invariant(importNode.type !== "TSImportEqualsDeclaration") */
// `import type` can only be used on imports with named imports or with a
// default import - but not both
if (
importNode.importKind === "type" &&
importNode.specifiers.length > 1 &&
importNode.specifiers[0].type === "ImportDefaultSpecifier"
) {
this.raise(
importNode.start,
"A type-only import can specify a default import or named bindings, but not both.",
);
}
return importNode;
} }
parseExport(node: N.Node): N.AnyExport { parseExport(node: N.Node): N.AnyExport {
@ -1888,6 +1911,13 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.semicolon(); this.semicolon();
return this.finishNode(decl, "TSNamespaceExportDeclaration"); return this.finishNode(decl, "TSNamespaceExportDeclaration");
} else { } else {
if (this.isContextual("type") && this.lookahead().type === tt.braceL) {
this.next();
node.exportKind = "type";
} else {
node.exportKind = "value";
}
return super.parseExport(node); return super.parseExport(node);
} }
} }
@ -2110,6 +2140,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (!declaration) { if (!declaration) {
declaration = super.parseExportDeclaration(node); declaration = super.parseExportDeclaration(node);
} }
if (
declaration &&
(declaration.type === "TSInterfaceDeclaration" ||
declaration.type === "TSTypeAliasDeclaration" ||
isDeclare)
) {
node.exportKind = "type";
}
if (declaration && isDeclare) { if (declaration && isDeclare) {
// Reset location to include `declare` in range // Reset location to include `declare` in range

View File

@ -0,0 +1 @@
export type from 'test';

View File

@ -0,0 +1,5 @@
{
"plugins": ["exportDefaultFrom", "typescript"],
"sourceType": "module",
"throws": "Unexpected token, expected \"=\" (1:17)"
}

View File

@ -43,6 +43,7 @@
"column": 26 "column": 26
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -110,6 +111,7 @@
"column": 29 "column": 29
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -176,6 +178,7 @@
"column": 16 "column": 16
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -226,6 +229,7 @@
"column": 21 "column": 21
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -291,6 +295,7 @@
"column": 18 "column": 18
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -356,6 +361,7 @@
"column": 21 "column": 21
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -421,6 +427,7 @@
"column": 27 "column": 27
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -43,6 +43,7 @@
"column": 24 "column": 24
} }
}, },
"exportKind": "value",
"declaration": { "declaration": {
"type": "Identifier", "type": "Identifier",
"start": 78, "start": 78,

View File

@ -144,6 +144,7 @@
"column": 27 "column": 27
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -229,6 +230,7 @@
"column": 33 "column": 33
} }
}, },
"exportKind": "value",
"declaration": { "declaration": {
"type": "ClassDeclaration", "type": "ClassDeclaration",
"start": 148, "start": 148,
@ -296,6 +298,7 @@
"column": 36 "column": 36
} }
}, },
"exportKind": "value",
"declaration": { "declaration": {
"type": "ClassDeclaration", "type": "ClassDeclaration",
"start": 182, "start": 182,

View File

@ -43,6 +43,7 @@
"column": 22 "column": 22
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -43,6 +43,7 @@
"column": 30 "column": 30
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -43,6 +43,7 @@
"column": 16 "column": 16
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -43,6 +43,7 @@
"column": 31 "column": 31
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -142,6 +143,7 @@
"column": 34 "column": 34
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -225,6 +227,7 @@
"column": 25 "column": 25
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -292,6 +295,7 @@
"column": 29 "column": 29
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -358,6 +362,7 @@
"column": 31 "column": 31
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -423,6 +428,7 @@
"column": 26 "column": 26
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -489,6 +495,7 @@
"column": 29 "column": 29
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -555,6 +562,7 @@
"column": 26 "column": 26
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -0,0 +1,4 @@
export type A = 2;
export interface B {}
export declare function a(): string;
export declare var b: string;

View File

@ -0,0 +1,370 @@
{
"type": "File",
"start": 0,
"end": 107,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 4,
"column": 29
}
},
"program": {
"type": "Program",
"start": 0,
"end": 107,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 4,
"column": 29
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start": 0,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 18
}
},
"exportKind": "type",
"specifiers": [],
"source": null,
"declaration": {
"type": "TSTypeAliasDeclaration",
"start": 7,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 18
}
},
"id": {
"type": "Identifier",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "A"
},
"name": "A"
},
"typeAnnotation": {
"type": "TSLiteralType",
"start": 16,
"end": 17,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 17
}
},
"literal": {
"type": "NumericLiteral",
"start": 16,
"end": 17,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 17
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
}
}
}
},
{
"type": "ExportNamedDeclaration",
"start": 19,
"end": 40,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 21
}
},
"exportKind": "type",
"specifiers": [],
"source": null,
"declaration": {
"type": "TSInterfaceDeclaration",
"start": 26,
"end": 40,
"loc": {
"start": {
"line": 2,
"column": 7
},
"end": {
"line": 2,
"column": 21
}
},
"id": {
"type": "Identifier",
"start": 36,
"end": 37,
"loc": {
"start": {
"line": 2,
"column": 17
},
"end": {
"line": 2,
"column": 18
},
"identifierName": "B"
},
"name": "B"
},
"body": {
"type": "TSInterfaceBody",
"start": 38,
"end": 40,
"loc": {
"start": {
"line": 2,
"column": 19
},
"end": {
"line": 2,
"column": 21
}
},
"body": []
}
}
},
{
"type": "ExportNamedDeclaration",
"start": 41,
"end": 77,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 36
}
},
"exportKind": "type",
"specifiers": [],
"source": null,
"declaration": {
"type": "TSDeclareFunction",
"start": 48,
"end": 77,
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 36
}
},
"id": {
"type": "Identifier",
"start": 65,
"end": 66,
"loc": {
"start": {
"line": 3,
"column": 24
},
"end": {
"line": 3,
"column": 25
},
"identifierName": "a"
},
"name": "a"
},
"generator": false,
"async": false,
"params": [],
"returnType": {
"type": "TSTypeAnnotation",
"start": 68,
"end": 76,
"loc": {
"start": {
"line": 3,
"column": 27
},
"end": {
"line": 3,
"column": 35
}
},
"typeAnnotation": {
"type": "TSStringKeyword",
"start": 70,
"end": 76,
"loc": {
"start": {
"line": 3,
"column": 29
},
"end": {
"line": 3,
"column": 35
}
}
}
},
"declare": true
}
},
{
"type": "ExportNamedDeclaration",
"start": 78,
"end": 107,
"loc": {
"start": {
"line": 4,
"column": 0
},
"end": {
"line": 4,
"column": 29
}
},
"exportKind": "type",
"specifiers": [],
"source": null,
"declaration": {
"type": "VariableDeclaration",
"start": 85,
"end": 107,
"loc": {
"start": {
"line": 4,
"column": 7
},
"end": {
"line": 4,
"column": 29
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 97,
"end": 106,
"loc": {
"start": {
"line": 4,
"column": 19
},
"end": {
"line": 4,
"column": 28
}
},
"id": {
"type": "Identifier",
"start": 97,
"end": 106,
"loc": {
"start": {
"line": 4,
"column": 19
},
"end": {
"line": 4,
"column": 28
},
"identifierName": "b"
},
"name": "b",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 98,
"end": 106,
"loc": {
"start": {
"line": 4,
"column": 20
},
"end": {
"line": 4,
"column": 28
}
},
"typeAnnotation": {
"type": "TSStringKeyword",
"start": 100,
"end": 106,
"loc": {
"start": {
"line": 4,
"column": 22
},
"end": {
"line": 4,
"column": 28
}
}
}
}
},
"init": null
}
],
"kind": "var",
"declare": true
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
export type { T } from './mod';

View File

@ -0,0 +1,123 @@
{
"type": "File",
"start": 0,
"end": 31,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 31
}
},
"program": {
"type": "Program",
"start": 0,
"end": 31,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 31
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start": 0,
"end": 31,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 31
}
},
"exportKind": "type",
"specifiers": [
{
"type": "ExportSpecifier",
"start": 14,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 1,
"column": 15
}
},
"local": {
"type": "Identifier",
"start": 14,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 1,
"column": 15
},
"identifierName": "T"
},
"name": "T"
},
"exported": {
"type": "Identifier",
"start": 14,
"end": 15,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 1,
"column": 15
},
"identifierName": "T"
},
"name": "T"
}
}
],
"source": {
"type": "StringLiteral",
"start": 23,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 23
},
"end": {
"line": 1,
"column": 30
}
},
"extra": {
"rawValue": "./mod",
"raw": "'./mod'"
},
"value": "./mod"
},
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1,2 @@
type A = 2;
export type { A };

View File

@ -0,0 +1,171 @@
{
"type": "File",
"start": 0,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 18
}
},
"program": {
"type": "Program",
"start": 0,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 18
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSTypeAliasDeclaration",
"start": 0,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 11
}
},
"id": {
"type": "Identifier",
"start": 5,
"end": 6,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 6
},
"identifierName": "A"
},
"name": "A"
},
"typeAnnotation": {
"type": "TSLiteralType",
"start": 9,
"end": 10,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 10
}
},
"literal": {
"type": "NumericLiteral",
"start": 9,
"end": 10,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 10
}
},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
}
}
},
{
"type": "ExportNamedDeclaration",
"start": 12,
"end": 30,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 18
}
},
"exportKind": "type",
"specifiers": [
{
"type": "ExportSpecifier",
"start": 26,
"end": 27,
"loc": {
"start": {
"line": 2,
"column": 14
},
"end": {
"line": 2,
"column": 15
}
},
"local": {
"type": "Identifier",
"start": 26,
"end": 27,
"loc": {
"start": {
"line": 2,
"column": 14
},
"end": {
"line": 2,
"column": 15
},
"identifierName": "A"
},
"name": "A"
},
"exported": {
"type": "Identifier",
"start": 26,
"end": 27,
"loc": {
"start": {
"line": 2,
"column": 14
},
"end": {
"line": 2,
"column": 15
},
"identifierName": "A"
},
"name": "A"
}
}
],
"source": null,
"declaration": null
}
],
"directives": []
}
}

View File

@ -0,0 +1,6 @@
export var a;
export function b() {}
export class C {}
export enum D {}
export namespace E {}

View File

@ -0,0 +1,358 @@
{
"type": "File",
"start": 0,
"end": 94,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 21
}
},
"program": {
"type": "Program",
"start": 0,
"end": 94,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 21
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExportNamedDeclaration",
"start": 0,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 13
}
},
"exportKind": "value",
"specifiers": [],
"source": null,
"declaration": {
"type": "VariableDeclaration",
"start": 7,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 7
},
"end": {
"line": 1,
"column": 13
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 11,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 12
}
},
"id": {
"type": "Identifier",
"start": 11,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 12
},
"identifierName": "a"
},
"name": "a"
},
"init": null
}
],
"kind": "var"
}
},
{
"type": "ExportNamedDeclaration",
"start": 14,
"end": 36,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 22
}
},
"exportKind": "value",
"specifiers": [],
"source": null,
"declaration": {
"type": "FunctionDeclaration",
"start": 21,
"end": 36,
"loc": {
"start": {
"line": 2,
"column": 7
},
"end": {
"line": 2,
"column": 22
}
},
"id": {
"type": "Identifier",
"start": 30,
"end": 31,
"loc": {
"start": {
"line": 2,
"column": 16
},
"end": {
"line": 2,
"column": 17
},
"identifierName": "b"
},
"name": "b"
},
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 34,
"end": 36,
"loc": {
"start": {
"line": 2,
"column": 20
},
"end": {
"line": 2,
"column": 22
}
},
"body": [],
"directives": []
}
}
},
{
"type": "ExportNamedDeclaration",
"start": 37,
"end": 54,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 17
}
},
"exportKind": "value",
"specifiers": [],
"source": null,
"declaration": {
"type": "ClassDeclaration",
"start": 44,
"end": 54,
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 17
}
},
"id": {
"type": "Identifier",
"start": 50,
"end": 51,
"loc": {
"start": {
"line": 3,
"column": 13
},
"end": {
"line": 3,
"column": 14
},
"identifierName": "C"
},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start": 52,
"end": 54,
"loc": {
"start": {
"line": 3,
"column": 15
},
"end": {
"line": 3,
"column": 17
}
},
"body": []
}
}
},
{
"type": "ExportNamedDeclaration",
"start": 56,
"end": 72,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 5,
"column": 16
}
},
"exportKind": "value",
"specifiers": [],
"source": null,
"declaration": {
"type": "TSEnumDeclaration",
"start": 63,
"end": 72,
"loc": {
"start": {
"line": 5,
"column": 7
},
"end": {
"line": 5,
"column": 16
}
},
"id": {
"type": "Identifier",
"start": 68,
"end": 69,
"loc": {
"start": {
"line": 5,
"column": 12
},
"end": {
"line": 5,
"column": 13
},
"identifierName": "D"
},
"name": "D"
},
"members": []
}
},
{
"type": "ExportNamedDeclaration",
"start": 73,
"end": 94,
"loc": {
"start": {
"line": 6,
"column": 0
},
"end": {
"line": 6,
"column": 21
}
},
"exportKind": "value",
"specifiers": [],
"source": null,
"declaration": {
"type": "TSModuleDeclaration",
"start": 80,
"end": 94,
"loc": {
"start": {
"line": 6,
"column": 7
},
"end": {
"line": 6,
"column": 21
}
},
"id": {
"type": "Identifier",
"start": 90,
"end": 91,
"loc": {
"start": {
"line": 6,
"column": 17
},
"end": {
"line": 6,
"column": 18
},
"identifierName": "E"
},
"name": "E"
},
"body": {
"type": "TSModuleBlock",
"start": 92,
"end": 94,
"loc": {
"start": {
"line": 6,
"column": 19
},
"end": {
"line": 6,
"column": 21
}
},
"body": []
}
}
}
],
"directives": []
}
}

View File

@ -43,6 +43,7 @@
"column": 19 "column": 19
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -130,6 +131,7 @@
"column": 1 "column": 1
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -192,6 +194,7 @@
"column": 23 "column": 23
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -43,6 +43,7 @@
"column": 42 "column": 42
} }
}, },
"exportKind": "value",
"declaration": { "declaration": {
"type": "TSDeclareFunction", "type": "TSDeclareFunction",
"start": 15, "start": 15,

View File

@ -43,6 +43,7 @@
"column": 37 "column": 37
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -173,6 +174,7 @@
"column": 37 "column": 37
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -111,6 +111,7 @@
"column": 13 "column": 13
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -92,6 +92,7 @@
"column": 27 "column": 27
} }
}, },
"importKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ImportNamespaceSpecifier", "type": "ImportNamespaceSpecifier",

View File

@ -43,6 +43,7 @@
"column": 21 "column": 21
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -108,6 +109,7 @@
"column": 29 "column": 29
} }
}, },
"exportKind": "value",
"declaration": { "declaration": {
"type": "TSInterfaceDeclaration", "type": "TSInterfaceDeclaration",
"start": 37, "start": 37,

View File

@ -43,6 +43,7 @@
"column": 23 "column": 23
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -140,6 +141,7 @@
"column": 18 "column": 18
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -43,6 +43,7 @@
"column": 23 "column": 23
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -107,6 +108,7 @@
"column": 16 "column": 16
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {
@ -157,6 +159,7 @@
"column": 21 "column": 21
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -109,6 +109,7 @@
"column": 15 "column": 15
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -43,6 +43,7 @@
"column": 15 "column": 15
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -94,6 +94,7 @@
"column": 26 "column": 26
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -43,6 +43,7 @@
"column": 26 "column": 26
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -91,6 +91,7 @@
"column": 13 "column": 13
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -43,6 +43,7 @@
"column": 13 "column": 13
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -91,6 +91,7 @@
"column": 13 "column": 13
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -90,6 +90,7 @@
"column": 13 "column": 13
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -43,6 +43,7 @@
"column": 13 "column": 13
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -160,6 +160,7 @@
"column": 13 "column": 13
} }
}, },
"exportKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ExportSpecifier", "type": "ExportSpecifier",

View File

@ -43,6 +43,7 @@
"column": 1 "column": 1
} }
}, },
"declare": true,
"id": { "id": {
"type": "Identifier", "type": "Identifier",
"start": 14, "start": 14,
@ -76,8 +77,7 @@
} }
}, },
"body": [] "body": []
}, }
"declare": true
}, },
{ {
"type": "TSModuleDeclaration", "type": "TSModuleDeclaration",
@ -139,6 +139,7 @@
"column": 22 "column": 22
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -43,6 +43,7 @@
"column": 1 "column": 1
} }
}, },
"declare": true,
"id": { "id": {
"type": "Identifier", "type": "Identifier",
"start": 14, "start": 14,
@ -76,8 +77,7 @@
} }
}, },
"body": [] "body": []
}, }
"declare": true
}, },
{ {
"type": "TSModuleDeclaration", "type": "TSModuleDeclaration",
@ -142,6 +142,7 @@
"column": 22 "column": 22
} }
}, },
"exportKind": "value",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -43,6 +43,7 @@
"column": 38 "column": 38
} }
}, },
"importKind": "value",
"specifiers": [ "specifiers": [
{ {
"type": "ImportDefaultSpecifier", "type": "ImportDefaultSpecifier",

View File

@ -43,6 +43,7 @@
"column": 23 "column": 23
} }
}, },
"exportKind": "type",
"specifiers": [], "specifiers": [],
"source": null, "source": null,
"declaration": { "declaration": {

View File

@ -0,0 +1 @@
import type FooDefault, { Bar, Baz } from "module";

View File

@ -0,0 +1,206 @@
{
"type": "File",
"start": 0,
"end": 51,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 51
}
},
"errors": [
"SyntaxError: A type-only import can specify a default import or named bindings, but not both. (1:0)"
],
"program": {
"type": "Program",
"start": 0,
"end": 51,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 51
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start": 0,
"end": 51,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 51
}
},
"importKind": "type",
"specifiers": [
{
"type": "ImportDefaultSpecifier",
"start": 12,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 22
}
},
"local": {
"type": "Identifier",
"start": 12,
"end": 22,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 22
},
"identifierName": "FooDefault"
},
"name": "FooDefault"
}
},
{
"type": "ImportSpecifier",
"start": 26,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 26
},
"end": {
"line": 1,
"column": 29
}
},
"imported": {
"type": "Identifier",
"start": 26,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 26
},
"end": {
"line": 1,
"column": 29
},
"identifierName": "Bar"
},
"name": "Bar"
},
"local": {
"type": "Identifier",
"start": 26,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 26
},
"end": {
"line": 1,
"column": 29
},
"identifierName": "Bar"
},
"name": "Bar"
}
},
{
"type": "ImportSpecifier",
"start": 31,
"end": 34,
"loc": {
"start": {
"line": 1,
"column": 31
},
"end": {
"line": 1,
"column": 34
}
},
"imported": {
"type": "Identifier",
"start": 31,
"end": 34,
"loc": {
"start": {
"line": 1,
"column": 31
},
"end": {
"line": 1,
"column": 34
},
"identifierName": "Baz"
},
"name": "Baz"
},
"local": {
"type": "Identifier",
"start": 31,
"end": 34,
"loc": {
"start": {
"line": 1,
"column": 31
},
"end": {
"line": 1,
"column": 34
},
"identifierName": "Baz"
},
"name": "Baz"
}
}
],
"source": {
"type": "StringLiteral",
"start": 42,
"end": 50,
"loc": {
"start": {
"line": 1,
"column": 42
},
"end": {
"line": 1,
"column": 50
}
},
"extra": {
"rawValue": "module",
"raw": "\"module\""
},
"value": "module"
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
import type T from './mod';
import type { A, B } from './mod';
import type * as Types from './mod';

View File

@ -0,0 +1,311 @@
{
"type": "File",
"start": 0,
"end": 99,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 36
}
},
"program": {
"type": "Program",
"start": 0,
"end": 99,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 36
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start": 0,
"end": 27,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 27
}
},
"importKind": "type",
"specifiers": [
{
"type": "ImportDefaultSpecifier",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
}
},
"local": {
"type": "Identifier",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "T"
},
"name": "T"
}
}
],
"source": {
"type": "StringLiteral",
"start": 19,
"end": 26,
"loc": {
"start": {
"line": 1,
"column": 19
},
"end": {
"line": 1,
"column": 26
}
},
"extra": {
"rawValue": "./mod",
"raw": "'./mod'"
},
"value": "./mod"
}
},
{
"type": "ImportDeclaration",
"start": 28,
"end": 62,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 34
}
},
"importKind": "type",
"specifiers": [
{
"type": "ImportSpecifier",
"start": 42,
"end": 43,
"loc": {
"start": {
"line": 2,
"column": 14
},
"end": {
"line": 2,
"column": 15
}
},
"imported": {
"type": "Identifier",
"start": 42,
"end": 43,
"loc": {
"start": {
"line": 2,
"column": 14
},
"end": {
"line": 2,
"column": 15
},
"identifierName": "A"
},
"name": "A"
},
"local": {
"type": "Identifier",
"start": 42,
"end": 43,
"loc": {
"start": {
"line": 2,
"column": 14
},
"end": {
"line": 2,
"column": 15
},
"identifierName": "A"
},
"name": "A"
}
},
{
"type": "ImportSpecifier",
"start": 45,
"end": 46,
"loc": {
"start": {
"line": 2,
"column": 17
},
"end": {
"line": 2,
"column": 18
}
},
"imported": {
"type": "Identifier",
"start": 45,
"end": 46,
"loc": {
"start": {
"line": 2,
"column": 17
},
"end": {
"line": 2,
"column": 18
},
"identifierName": "B"
},
"name": "B"
},
"local": {
"type": "Identifier",
"start": 45,
"end": 46,
"loc": {
"start": {
"line": 2,
"column": 17
},
"end": {
"line": 2,
"column": 18
},
"identifierName": "B"
},
"name": "B"
}
}
],
"source": {
"type": "StringLiteral",
"start": 54,
"end": 61,
"loc": {
"start": {
"line": 2,
"column": 26
},
"end": {
"line": 2,
"column": 33
}
},
"extra": {
"rawValue": "./mod",
"raw": "'./mod'"
},
"value": "./mod"
}
},
{
"type": "ImportDeclaration",
"start": 63,
"end": 99,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 36
}
},
"importKind": "type",
"specifiers": [
{
"type": "ImportNamespaceSpecifier",
"start": 75,
"end": 85,
"loc": {
"start": {
"line": 3,
"column": 12
},
"end": {
"line": 3,
"column": 22
}
},
"local": {
"type": "Identifier",
"start": 80,
"end": 85,
"loc": {
"start": {
"line": 3,
"column": 17
},
"end": {
"line": 3,
"column": 22
},
"identifierName": "Types"
},
"name": "Types"
}
}
],
"source": {
"type": "StringLiteral",
"start": 91,
"end": 98,
"loc": {
"start": {
"line": 3,
"column": 28
},
"end": {
"line": 3,
"column": 35
}
},
"extra": {
"rawValue": "./mod",
"raw": "'./mod'"
},
"value": "./mod"
}
}
],
"directives": []
}
}

View File

@ -50,6 +50,7 @@ export default declare(
jsxPragma = "React", jsxPragma = "React",
allowNamespaces = false, allowNamespaces = false,
allowDeclareFields = false, allowDeclareFields = false,
onlyRemoveTypeImports = false,
}, },
) => { ) => {
api.assertVersion(7); api.assertVersion(7);
@ -166,43 +167,52 @@ export default declare(
// remove type imports // remove type imports
for (let stmt of path.get("body")) { for (let stmt of path.get("body")) {
if (t.isImportDeclaration(stmt)) { if (t.isImportDeclaration(stmt)) {
// Note: this will allow both `import { } from "m"` and `import "m";`. if (stmt.node.importKind === "type") {
// In TypeScript, the former would be elided. stmt.remove();
if (stmt.node.specifiers.length === 0) {
continue; continue;
} }
let allElided = true; // If onlyRemoveTypeImports is `true`, only remove type-only imports
const importsToRemove: Path<Node>[] = []; // and exports introduced in TypeScript 3.8.
if (!onlyRemoveTypeImports) {
for (const specifier of stmt.node.specifiers) { // Note: this will allow both `import { } from "m"` and `import "m";`.
const binding = stmt.scope.getBinding(specifier.local.name); // In TypeScript, the former would be elided.
if (stmt.node.specifiers.length === 0) {
// The binding may not exist if the import node was explicitly continue;
// injected by another plugin. Currently core does not do a good job
// of keeping scope bindings synchronized with the AST. For now we
// just bail if there is no binding, since chances are good that if
// the import statement was injected then it wasn't a typescript type
// import anyway.
if (
binding &&
isImportTypeOnly({
binding,
programPath: path,
jsxPragma: fileJsxPragma || jsxPragma,
})
) {
importsToRemove.push(binding.path);
} else {
allElided = false;
} }
}
if (allElided) { let allElided = true;
stmt.remove(); const importsToRemove: Path<Node>[] = [];
} else {
for (const importPath of importsToRemove) { for (const specifier of stmt.node.specifiers) {
importPath.remove(); const binding = stmt.scope.getBinding(specifier.local.name);
// The binding may not exist if the import node was explicitly
// injected by another plugin. Currently core does not do a good job
// of keeping scope bindings synchronized with the AST. For now we
// just bail if there is no binding, since chances are good that if
// the import statement was injected then it wasn't a typescript type
// import anyway.
if (
binding &&
isImportTypeOnly({
binding,
programPath: path,
jsxPragma: fileJsxPragma || jsxPragma,
})
) {
importsToRemove.push(binding.path);
} else {
allElided = false;
}
}
if (allElided) {
stmt.remove();
} else {
for (const importPath of importsToRemove) {
importPath.remove();
}
} }
} }
@ -232,7 +242,18 @@ export default declare(
}, },
ExportNamedDeclaration(path) { ExportNamedDeclaration(path) {
if (path.node.exportKind === "type") {
path.remove();
return;
}
// remove export declaration if it's exporting only types // remove export declaration if it's exporting only types
// This logic is needed when exportKind is "value", because
// currently the "type" keyword is optional.
// TODO:
// Also, currently @babel/parser sets exportKind to "value" for
// export interface A {}
// etc.
if ( if (
!path.node.source && !path.node.source &&
path.node.specifiers.length > 0 && path.node.specifiers.length > 0 &&

View File

@ -0,0 +1,2 @@
export type { A } from "./mod";
;

View File

@ -0,0 +1,4 @@
type A = 2;
export type { A };
;

View File

@ -0,0 +1,13 @@
import a from "a";
import { b } from "b";
import { c as c2 } from "c";
import d, { d2 } from "d";
import e, { e3 as e4 } from "e";
import {} from "f";
import "g";
import type H from "h";
import type { I, I2 } from "i";
import type * as J from "j";
;

View File

@ -0,0 +1,3 @@
import "f";
import "g";
;

View File

@ -0,0 +1,4 @@
import type A from "x";
// TODO: This should not be removed
import B from "y";
;

View File

@ -0,0 +1,2 @@
// TODO: This should not be removed
;

View File

@ -0,0 +1,4 @@
import type T from './mod';
import type { A, B } from './mod';
import type * as Types from './mod';
;

View File

@ -0,0 +1,13 @@
import a from "a";
import { b } from "b";
import { c as c2 } from "c";
import d, { d2 } from "d";
import e, { e3 as e4 } from "e";
import {} from "f";
import "g";
import type H from "h";
import type { I, I2 } from "i";
import type * as J from "j";
;

View File

@ -0,0 +1,8 @@
{
"plugins": [[
"transform-typescript",
{
"onlyRemoveTypeImports": true
}
]]
}

View File

@ -0,0 +1,8 @@
import a from "a";
import { b } from "b";
import { c as c2 } from "c";
import d, { d2 } from "d";
import e, { e3 as e4 } from "e";
import "f";
import "g";
;

View File

@ -5,11 +5,12 @@ export default declare(
( (
api, api,
{ {
jsxPragma,
allExtensions = false, allExtensions = false,
isTSX = false,
allowNamespaces,
allowDeclareFields, allowDeclareFields,
allowNamespaces,
jsxPragma,
isTSX = false,
onlyRemoveTypeImports,
}, },
) => { ) => {
api.assertVersion(7); api.assertVersion(7);
@ -27,10 +28,11 @@ export default declare(
} }
const pluginOptions = isTSX => ({ const pluginOptions = isTSX => ({
jsxPragma,
isTSX,
allowNamespaces,
allowDeclareFields, allowDeclareFields,
allowNamespaces,
isTSX,
jsxPragma,
onlyRemoveTypeImports,
}); });
return { return {

View File

@ -382,7 +382,8 @@ defineType("ImportDeclaration", {
validate: assertNodeType("StringLiteral"), validate: assertNodeType("StringLiteral"),
}, },
importKind: { importKind: {
// Handle Flowtype's extension "import {typeof foo} from" // Handle TypeScript/Flowtype's extension "import type foo from"
// TypeScript doesn't support typeof
validate: assertOneOf("type", "typeof", "value"), validate: assertOneOf("type", "typeof", "value"),
optional: true, optional: true,
}, },