TypeScript 仅仅导入声明语法

一种「预期」的行为

在 TypeScript 中,如果导入的模块没有用于任何表达式,TypeScript 将会删除该模块导入。

import { xxx } from './module';

let a: xxx = /* something */;
复制代码

编译后:

var a = /* ssomething */;
复制代码

如果你需要强制导入该模块,你可以使用 import 'module' 语法:

import './module';
复制代码

这有时候非常糟糕,试想如果一个模块如果含有副作用,但是并没有用到任何表达式中:

// source-component.ts
export class SourceComponent extends HTMLElement {
  // 其他代码
}
customElements.define('source-component', SourceComponent);
复制代码
import {SourceComponent} from './source-component.js';

const example = document.createElement('source-component') as SourceComponent;
复制代码

在正常编译时,TypeScript 将会在编码者毫不知情的情况下舍弃 source-component.ts 文件。待到提测阶段,你可能才会发现问题所在,查找、抱怨之后,会加上 import './source-component.js' 这样一行代码,来让编译器强制导入该模块。

其次,使用 isolatedModules 编译选项时,以下代码。会出现编译错误的问题:

export { AType } from './module' // Cannot re-export a type when the '--isolatedModules' flag is provided
复制代码

在笔者查阅相关资料后,了解到 isolatedModules 编译选项,其实是「确保我的程序代码可以被不进行任何类型检查的编译器正确地编译」(如 babel)。

当在 babel 运行以下程序时,也会抛出错误:

// Export 'MyType' is not defined
export { MyType } from './module';
复制代码

为了正常编译通过,你需要改成如下方式:

import { AType as BType } from './module';
export type AType = BType;

// 或者
export type AType = import('./module').AType
复制代码

仅导入/导出类型

在即将到来的 3.8 版本中,有一个提案 import type,旨在解决上述中的问题。

它提供了以下语法:

import type T from './mod';
import type { A, B } from './mod';
import type * as Types from './mod';

export type { T };
export type { T } from './mod';
复制代码

import type 用来告诉 TypeScript 编译器,仅仅是导入/导出类型:

// a.ts
export default calss A{}

// b.ts
import type A from './a';

new A(); // error,

function f(obj: A) {} // ok
复制代码

因此在默认情况下,TypeScript 将不会再删除任何 import 导入语句:

import { T } from './module';
import x: T;
复制代码

编译后:

import "./module";
let x;
复制代码

并且对于在使用 isolatedModules 编译选项时,export { AType } from './module' 的问题,只需改写成 export type { T } from './mod'; 即可解决。

ps: TypeScript 3.8 大概在 2020 年 2 月发布。

参考

如果你对 TypeScript 感兴趣,可以通过京东、当当等渠道购买《深入理解 TypeScript》。

或者你也可以关注下面公众号,获取更多内容

分类:
前端
标签: