【Typescript小手册】配置文件

355 阅读6分钟

概述

Typescript 会根据配置文件来设定编译编译方式和细节,这篇文章来讲讲 Typescript 编译配置文件常用的选项的含义。它的编译选项非常多,更多内容可参考官方文档Intro to the TSConfig Reference

对于初学者而言,不需要一开始就掌握这一部分内容,可以选择先跳过本章节。

我们可以通过tsc --init命令来让 Typescript 帮你生成一个配置文件,里面也所有配置项及相应的说明。


配置

按照功能,配置可以分为 9 类:

  • 文件
  • 项目
  • 约束
  • 模块解析
  • 代码映射
  • 风格检查
  • 命令行
  • 观察
  • 高级

其中后 8 类属性编写在compilerOptions对象中。


文件

files

类型:数组。

控制需要进行编译的文件路径,可以省略后缀名 ts。

示例:

{
  "files": ["src/a.ts"]
}

include

类型:数组。

控制需要进行编译的文件路径,与 files 不同的是可以使用通配符*(表示文件)、**(比较目录)和?(表示字符)。

示例:

{
  "include": ["src/**/*"]
}

表示编辑 src 目录下的所有 ts 文件。

如果没有配置 include,则编译工作目录下的所有 ts 文件,相当于设置为["**/*"]

exclude

类型:数组。默认值为:["node_modules", "bower_components", "jspm_packages"]和配置 outDir 指定的文件夹。

用于排除不需要编译的文件,可以使用与 include 相同的通配符。

exclude 只是对 include 的修饰,如果一个文件处在 files 列表、被import语句导入、被/// <reference>语句指定或是类型文件的,exclude 配置无法将其排除。

extends

类型:字符串。

值含义是另一个配置文件的路径,本配置文件会在继承被引入的配置文件的基础上融合。files、include、exclude 直接覆盖,references 无法继承。

项目

target

类型:字符串。默认:ES3

控制生成的 js 文件所使用的 ES 版本。可选值可参考:tsconfig#target,其中ESNEXT是个比较特殊的值,它表示使用当前 Typescript 版本支持的最新的 ES 版本。

lib

类型:字符串数组。

不同的 Javascript 运行环境和 ES 版本有不同 API,lib 控制哪些 API 可以被使用,本质上是引入相对应的类型声明文件。

target 选项会影响 lib 的默认值,对应目标环境的 API 会被自动引入。

示例:

{
  "compilerOptions": {
    "lib": ["ES2015", "DOM"]
  }
}

这样配置之后,在代码中就可以使用 ES2015 和 DOM 中的 API。如果想要查询 Typescript 内置对象的 API,可以查询 node_modules/typescript/lib 中的声明文件。

更多可配置的选项可见:tsconfig#lib

module

类型:字符串。

控制编译结果的模块系统,常用的有:CommonJSES6

target 选项会影响 module 的默认值。

outDir

类型:布尔。默认:false

默认情况下,生成的文件(包括 js 文件、d.ts 文件和代码映射文件)与 ts 源文件在同一目录下。设置了 outDir 后,输出文件被转移至对应目录,且目录结构仍然保留。输出目录中的第一层目录有选项 rootDir 控制。

rootDir

类型:字符串。

当设置了 outDir,控制输出文件目录结构的根目录。默认值是所有非声明文件的 ts 文件的最长公共路径。

比如,如果源代码目录结构是这样的,设置了"outDir": "out"

Workspace
├── tsconfig.json
├── src
│   ├── a.ts
│   ├── b.ts
│   ├── sub
│   │   ├── c.ts
├── types.d.ts

那么输出结构为。

Workspace
├── out
│   ├── a.js
│   ├── b.js
│   ├── sub
│   │   ├── c.js

如果设置了 rootDir,那么输出文件夹中的第一层目录就是指定的目录。比如设置"outDir": "./",那么输出结构为。

Workspace
├── out
│   ├── src
│   │    ├── a.js
│   │    ├── b.js
│   │    ├── sub
│   │    │   ├── c.js

outFile

类型:布尔。默认:false

设置一个文件路径,将所有代码打包到一个文件内。

要求 module 设置为SystemAMD

noEmit

类型:布尔。默认:false

设置为true后不会产生输出文件,结果值保存在内容中,通常在其它编译工具(入 Babel)中使用。

declaration

类型:布尔。默认:false

自动生成声明文件(.d.ts)。

sourceMap

类型:布尔。默认:false

生成代码映射文件。

importHelpers

类型:布尔。默认:false

在运行时引入辅助库。

Typescript 在编译模块文件中的新语法为旧语法(比如从 ES6 到 ES5)时,需要引入一些辅助函数。默认情况下,这些辅助函数被硬编码到使用处。为了压缩代码,开启 importHelpers 会使得辅助函数在运行时被引用,这样可以减少代码量。

示例:

export function copy(arg: string[]) {
  return [...arg]
}

这个 ts 文件中使用了 ES6 的扩展运算符。当不使用 importHelpers 时,被编译成:

'use strict'
var __spreadArrays =
  (this && this.__spreadArrays) ||
  function () {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length
    for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]
    return r
  }
exports.__esModule = true
exports.copy = void 0
function copy(arg) {
  return __spreadArrays(arg)
}
exports.copy = copy

如果开启了importHelpers,被编译成:

'use strict'
exports.__esModule = true
exports.copy = void 0
var tslib_1 = require('tslib')
function copy(arg) {
  return tslib_1.__spreadArrays(arg)
}
exports.copy = copy

注意:使用此功能时,编译时和运行时环境都需要 tslib 库(NPM 安装)。

allowJs

类型:布尔。默认:false

允许在 ts 文件中引入 js 文件。

checkJs

类型:布尔。默认:false

检查在 ts 文件中引入的 js 文件的语法。

removeComments

类型:布尔。默认:false

删除注释。

约束

strict

类型:布尔。默认:false

代码检查时遵循严格模式,同时开启:

  • alwaysStrict
  • strictNullChecks
  • strictBindCallApply
  • strictFunctionTypes
  • strictPropertyInitialization
  • noImplicitAny
  • noImplicitThis

alwaysStrict

类型:布尔。默认:false

使用严格模式编译 ts 文件,在生成的 js 文件中使用'use strict'

onImplicitAny

类型:布尔。默认:false

禁止使用不明确的any类型。

示例:

function slice(arg) {
  return arg.slice(0, 1)
}

这一段代码中,由于没有声明参数arg的类型,编译器推测argany类型。如果设置了"noImplicit": true,那就会报错,必须显示声明为any类型,即:function slice(arg: any)

onImplicitThis

类型:布尔。默认:false

禁止this具有不明确的类型。

这种情况通常发生在高等函数中,比如:

class GetLog {
  get() {
    return function log() {
      console.log(this)
    }
  }
}

log函数不是GetLog类的对象,而是由GetLog类方法生成的函数,其 this 指向并不是GetLog类的实例,而是全局对象或undefined,可能会违背这个函数的设计目的。

strictBindCallApply

类型:布尔。默认:false

限制函数的callapplybind方法的传参为函数的参数类型。

示例:

function parse(arg: string) {
  return parseInt(arg)
}

parse.call(undefined, true)

因为true不是string类型值,所以编译器报错提示类型错误。

如果没有开启这个选项,那么编译器不会报错,且callapplybind方法的返回值为any类型。

strictFunctionTypes

类型:布尔。默认:false

严格的函数类型检查。

在未开启这个选项时,编译器会包容一些可能发生的联合类型错误,将错误的报告延迟到运行时。

示例:

function log(arg: string) {
  console.log(arg.toLowerCase())
}

type StringOrNumberFunc = (arg: string | number) => void

let f: StringOrNumberFunc = log
f(1)

由于log只接受字符串类型的参数,但是f可以接受字符串或数字的参数,所以两者之间的参数类型没有完全匹配,如果将数字传入f函数就会报错。

设置了"strictFunctionTypes": true后可以避免这个问题,在编译阶段编译器会报告这一可能发生的错误。

注意:这一特性仅适用于function函数,不适用对象或类方法。

strictNullChecks

类型:布尔。默认:false

严格检查nullundefined

在未开启这个选项时,nullundefined可以被其它类型的变量兼容,进而在运行时可能出错。

示例:

let array = []
let target = array.find(a => a.name === 'a')
console.log(target.name)

array是空数组,target必定为undefined,所以在执行target.name时会报错。

如果设置了"strictNullChecks": true,这一问题在编译阶段会被报告出来。

strictPropertyInitialization

类型:布尔。默认:false

禁止在class声明中,类属性被声明但是没有被初始化(声明初始化或构造函数初始化)。

模块解析

baseUrl

类型:字符串。

引入非绝对地址模块的基地址。

moduleResolution

类型:字符串。

控制模块的搜索策略,即对于引入 ts 的其它 ts 文件或模块,编译其如何找到其源文件。

可选值有nodeclassic,其中classic主要用于向后兼容,一般常用node

可多细节可查看 Typescript 文档:module-resolution

esModuleInterop

类型:布尔。默认:false

辅助解决 ES 模块中引入 CommonJs 模块时的问题,主要针对 ESM 中有默认导出而 CommonJs 没有。

开启后 allowSyntheticDefaultImports 会被默认开启。

更多细节可查看 Typescript 文档:tsconfig#esModuleInterop

allowSyntheticDefaultImports

类型:布尔。默认:false

将全部导出转换为默认导出。

如果一个模块,没有默认导出,那我们需要已这样的方式引入全部变量:

import * as _ from 'lodash'

设置了"allowSyntheticDefaultImports": true后,我们可以以默认导出的方式引入模块:

import _ from 'lodash'

paths

类型:对象。

控制模块路径的重映射,也可以理解为路径别名。

示例:

{
  "compilerOptions": {
    "baseUrl": "."
    "paths": {
      "@/*":["src/*"],
      "jquery": ["node_modules/jquery/dist/jquery"]
    }
  }
}

在这个例子中,一个条配置使得无论当前编写的文件在目录结构中的什么位置,或是与 src 中目标文件的相对关系如何,都可以直接使用@前缀且相对于 baseUrl 的路径来访问;第二条配置,显示的设置了 jquery 的位置。

使用这个选项前必须设置 baseUrl。