配置typeScript编辑器(二)

TypeScript 是 ES6 的超集,因此您实际上是使用 ES6 版本的 JavaScript 编写 TS 代码。但是,在编译时,生成的 JS 代码可以是 ES5 或更早版本。你需要定义编译器应该编译成哪个版本的 JS。这可以使用target选项设置:

1
2
3
4
5
{ "compilerOptions": { "target": "es6" } }

您可以使用 ES6 modules编写 TS 源代码,但截至 2016 年 1 月,没有浏览器原生支持module。因此,您可能希望将 ES6 modules编译到不同的module system中:CommonJS、AMD、SystemJS。这可以使用module选项来完成。有一些构建时或运行时的转译器可以将 ES6 module system转译为构建系统(Webpack)或模块加载器(SystemJS)支持的模块系统之一。如果没有指定,如果 target 是 ES6, 模块默认为 ES6,否则为 CommonJS。 我更喜欢显式地将目标设置为 CommonJS

1
2
3
4
5
{ "compilerOptions": { "module": "CommonJS" } }

TS 支持 ES7 提案中的decorators(装饰器) 。例如,它们在 Angular2 TS 开发过程中大量使用 。为了能够在 TS 源代码中使用装饰器,应该设置以下选项:

1
2
3
4
5
{ "compilerOptions": { "experimentalDecorators": true } }

Angular2 DI 还使用元数据信息来理解要注入的依赖类型。要在输出中显示此元数据,请使用 emitDecoratorMetadata 选项:

1
2
3
4
5
6
{ "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true } }

为了能够在 TS 源代码中使用 ES 标准库中的类,您应该使用 lib 选项并指定源代码中使用的所有标准 ES6 库接口 。例如,要使用 ES6DOM 中的 Reflect 对象或 Array.from, 请配置以下内容:

1
2
3
4
5
{ "compilerOptions": { "lib": ["es6", "dom"], } }

默认情况下,TS 包括ES5的 DOMES5ScriptHost 和 ES6 的 DOM,ES6,DOM.Iterable,ScriptHost 。如果设置 lib 选项,编译器不会自动注入默认库,必须手动列出。

注意:通过指定 lib, 你可以简单地告诉 TS 编译器,如果在编译过程中遇到这些库中的类或 API,不要抛出错误。此选项对输出没有影响,因为库只是一个带有 lib API 接口的 d.ts 文件。

Module resolution

将模块解析策略设置为node后,TS 编译器会在 node_modules 文件夹中查找模块。但如果您的模块位于另一个文件夹中,您可以使用路径选项将自定义文件夹添加到要查找模块的文件夹列表中。假设,在你的 TS 代码中,你引用了这样一个模块:

1
import { jQuery} from 'jquery';

你的 jquery 文件夹放在 libs 文件夹里。因此,您可以使用以下配置

1
2
3
4
5
6
7
8
9
10
{ "compilerOptions": { "baseUrl": ".", "paths": { "jquery": [ "libs/jquery" ] } } }

这告诉编译器,当 jquery 模块被引用时,它应该去看 libs/jquery 内部。编译器将首先在lib文件夹中查找 jquery.[ts|d.ts], 如果没有找到, 将会继续在 libs/jquery中查找。它将首先尝试定位 package.json 文件,并使用 typings 属性指定主文件,如果找不到,则将默认为 index.[ts|d.ts]。

你可以使用 * 来匹配任何模块。因此,上述配置可以替换为以下配置

1
2
3
4
5
6
7
8
9
10
{ "compilerOptions": { "baseUrl": ".", "paths": { "*": [ "libs/*" ] } } }

如果使用 --traceResolution, 您将看到以下内容:

1
2
Module name 'jquery', matched pattern '*'. Trying substitution 'libs/*', candidate module location: 'libs/jquery'.

可以看到编译器将路径中的星号替换为匹配的模式。这给了我们很大的灵活性,因为我们可以匹配模块名称的一部分。一个常见的用例是模块名称与目录结构不匹配。例如,您在代码中引用库,如下所示:

1
import { jQuery } from 'package/vendors/jquery';

在你的目录结构中,jquery 库被放在 libs 文件夹中。通过以下配置,编译器将能够定位 jquery 库:

1
2
3
4
5
6
7
8
9
10
{ "compilerOptions": { "baseUrl": ".", "paths": { "package/vendors/*": [ "libs/*" ] } } }

注意:如果您设置了 paths 选项,则 baseUrl 是必需的。它指定要在其中解析非相对模块的基目录。

如果设置了 paths 选项,编译器将遍历在 paths 中定义的文件夹,并且仅在未找到任何内容时才检查 node_modules 文件夹。使用第一个解析的模块,不检查其他路径。因此,如果你有一个模块同时放在 node_modules 和你的自定义文件夹中,编译器将选择自定义文件夹中的模块。如果需要编译器使用 node_modules 文件夹中的模块,请将其添加到自定义文件夹之前的路径中:

1
2
3
4
5
6
7
8
9
10
11
12
{ "compilerOptions": { "baseUrl": ".", "paths": { "*": [ "*", "node_modules/*", "generated/*" ] } } }

使用声明文件

TypeScript 提供了一种机制来定义一个成员(变量/类),它不会被转译成 JavaScript,并且实际的实现预计在运行时可用。此功能旨在支持与现有 JavaScript 代码的集成,例如浏览器 API 或 jQuery 等开源库。
当你使用一个没有在 TS 项目文件中定义的对象时,编译器会报告错误:

1
2
logger.log(); Error:(2, 1) TS2304:Cannot find name 'logger'.

要解决此问题,您可以编写以下代码:

1
2
declare var logger: {log: () => void}; logger.log();

这被称为ambient declaration(环境声明),环境声明没有任何输出,只在编译期间使用。环境声明是使用 declare 关键字创建的。这样的声明, TS 提供了一个特殊的文件类型来分组他们-声明文件,具有 .d.ts 扩展名。这些文件只能包含环境声明,并且在开发过程中大量使用。例如,当您在代码中使用 console.log() 时,TS 不会报告错误,因为控制台对象已经在 typescript npm 包附带的 lib.d.ts 文件中定义。

您很可能需要自己生成和使用declaration files。这些文件不包含实际的实现,但定义了运行时可用的类 API 和值。要让编译器发出 .d.ts 文件,请使用声明选项:

1
2
3
"compilerOptions": { "declaration": true }

有时,将声明文件输出到单独的目录或事件将它们全部连接到一个文件中会很方便。它们的位置可以使用 declarationDir 选项定义:

1
2
3
4
5
6
{ "compilerOptions": { "declaration": true, "declarationDir": "declarations" } }

并使用 outFile 选项连接(与生成的 .js 文件相同):

1
2
3
4
5
6
{ "compilerOptions": { "declaration": true, "outFile": "declarations/index.d.ts" } }

检查生成的 .d.ts 文件时,您可能会看到以下内容:

1
2
declare module "module1" { ... } declare module "module2" { ... }

这实际上是在 1.5 之前用于 external/ES6 模块的语法。它现在用于支持在一个文件中声明多个 ES6 模块,并且只能在声明文件中使用。

1
2
declare module module1 { ... } declare module module2 { ... }

这种不带引号的名称格式在 1.5 之前用于声明namespaces 。从 1.5 开始,不鼓励使用这种格式,建议用 namespace 关键字替换:

1
2
declare namespace module1 { ... } declare namespace module2 { ... }

与带引号的模块名称不同,命名空间可以在 ts 和 d.ts 文件中使用。