Skip to content
On this page

TypeScript

TypeScript 笔记,基于 官方文档@wangtunan@maomao 的慷慨分享

基础

原始类型

  • string
  • number
  • boolean
  • symbol
  • bigint
  • null
  • undefined

null 与 undefined

  • 非空断言

非空断言采用 !. 操作符,用以移除 nullundefined 类型,类似于 JavaScript 可选链操作符 ?.

ts
function liveDangerously(x?: number | null) {
  console.log(x!.toFixed())
}
  • strictNullChecks strictNullChecks 开启严格空值检查模式
json
// tsconfig.json
{
  "strictNullChecks": true
}

该模式下, nullundefined 只允许被分配给自己或 any 类型的变量

ts
const a: null = null
const b: undefined = undefined
const c: any = null

const err: number = null // Type 'null' is not assignable to type 'number'

访问一个可能是 nullundefined 类型的变量属性或方法时,需先进行类型收窄

ts
function printLength(value?: string | null) {
  if (typeof value === 'string') {
    console.log(value.length)
  }
}

任意值

any 是一个特殊的类型,当一个值是 any 类型的时候, TypeScript 将不会对其进行类型检查

ts
// 如同写 js,你可以任意操作你的变量,TypeScript 并不会抛出相关的提示
let free: any = 1
free = { name: 'donggua' }
free.log()
free = 'any'
noImplicitAny

noImplicitAny 严格检查类型,不允许任何隐式 any 类型

json
// tsconfig.json
{
  "noImplicitAny": true
}
ts
function fn(s) {
  // Parameter 's' implicitly has an 'any' type
  console.log(s.subtr(3))
}

WARNING

无论是开发者指定或是由 TypeScript 隐式推断出的 any 类型,都会导致 TypeScript 失去准确的类型推断能力。可能会导致遗漏一些运行时错误,违背使用 TypeScript 的初衷。

Unknown

unknown 用于描述一个我们还不知道其类型的变量

ts
let notSure: unknown = 4
notSure = 'maybe a string instead'

// OK, definitely a boolean
notSure = false

unknown VS any

相比于 any 不会对变量进行任何检查,对于 unknown 类型的变量在执行大多数操作时必须进行相应的检查,因此 unknown 类型相对更加严格

字面量

除了常见的类型,还可以将类型声明为具体的数字或者字符串,常用于 联合类型

ts
const demo: 'demo' = 'demo'

// 更常用的联合类型
type Alignment = 'left' | 'right' | 'center'

对象

定义对象类型,可以罗列属性和对应的类型

ts
const obj: { name: string; job: string } = {
  name: 'donggua',
  job: 'fe'
}

在 JavaScript 中访问对象还可以使用方括号 [] 作为属性访问器,TypeScript 也提供了对应的 索引访问类型

即通过 [] 进行索引签名访问,并以此创建 映射类型

ts
const obj: { [key: string]: string } = {
  name: 'donggua',
  job: 'fe'
}

函数

TypeScript 允许指定函数的参数类型和返回类型

ts
function sum(a: number, b: number): number {
  return a + b
}

空值

对于没有返回值的函数,用 void 进行声明注解

ts
function log(): void {
  console.log('TypeScript is Cool!')
}

匿名函数

不同于函数声明,TypeScript 会根据 上下文推断 为匿名函数指定正确的类型

ts
const names = ['Alice', 'Bob', 'Eve'] // 此处不做类型注解

names.forEach(function (s) {
  console.log(s.toUppercase())
  // Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
})

// 箭头函数同样支持
names.forEach(s => {
  console.log(s.toUppercase())
  // Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
})

Never

never 类型表示的是那些永不存在的值的类型,更多的用于表示函数无法达到终点

ts
function errorHandler(message: string): never {
  throw new Error(message)
}

function infiniteLoop(): never {
  while (true) {}
}

数组与元组

  • 数组类型声明有 类型[] 以及 泛型 两种形式
ts
const queues: number[] = [1, 2, 3]
const stack: Array<number> = [1, 2, 3]
  • 元组相当于固定长度的数组,并且已知数组每项对应的的类型

对元祖类型的数据进行 越界访问分配错误的类型值 时,TypeScript 将报错提示

ts
type Tuple = [string, number]
const tuple: Tuple = ['donggua', 123]
tuple[0] = 666 // Type 'number' is not assignable to type 'string'
console.log(tuple[2]) // Tuple type 'Tuple' of length '2' has no element at index '2'

类型别名与接口

  • 类型别名即使用关键字 type 指定基础类型、对象类型、联合类型等任意类型的命名,类似于 JavaScript 中的 let
ts
type ID = number
type Person = {
  name: string
  age: number
}
  • 接口是指定对象类型命名的另一种形式
ts
interface Person {
  name: string
  age: number
}
type VS interface
  • 二者都可以用来声明对象或函数签名,仅语法不同
ts
// type
  type Person = {
    name: string;
    sex: number;
  }
  type Params = (a: number, b: number) => void

  // interface
  interface Person {
    name: string;
    sex: number;
  }
  interface Params {
    (a: number, b: number) => void
  }
  • 二者可以相互拓展,type 借助 &interface 借助 extends
ts
// type extends type
type Parameter = { a: number };
type Result = Parameter & { b: number };

// interface extends interface
interface Parameter = { a: number };
interface Result extends Parameter {
  b: number;
};
// type extends interface
interface Parameter = { a: number };
type Result = Parameter & { b: number };

// interface extends type
type Parameter = { a: number };
interface Result extends Parameter {
  b: number;
};
// 接口只能扩展对象类型或对象类型与静态已知成员的交集
type Parameter = { a: number } | { b: number };
// An interface can only extend an object type or intersection of
// object types with statically known members.
interface Result extends Parameter {
  c: number;
}
  • type 可用于声明基础类型、联合类型、元组,而 interface 不行
ts
type str = string
type Union = string | number
type tuple = [string, number]
  • 类可以实现接口或类型别名,但不可实现联合类型的类型别名
ts
type UnionAlias = { a: number } | { b: number }
class Demo implements UnionAlias {}
// A class can only implement an object type or intersection of object types
// with statically known members

TIP

类似 letconst 的选择,一般情况下建议使用 interface ,在不支持的情况下再使用 type 类型别名

类型推断与类型注解

  • 类型注解:显式指定变量的类型
  • 类型推断:由 TypeScript 根据上下文内容自动推断出变量类型
ts
let nickname: string = 'donggua'
let job = 'FE' // TypeScript 自动推断为 job: string

TIP

  • 在为变量赋值明确的值时,建议尽量使用 类型注解 的方式
  • 对于函数返回值,始终显示指明返回类型是个更好的习惯

联合类型与交叉类型

  • 联合类型是由两个或者更多类型组成的类型,并用 | 连接,表示值可能是这些类型中的任意一个
ts
function print(value: number | string): void {
  console.log(value)
}
  • 交叉类型是由多个类型的成员合并,用 & 连接,表示取所有成员的类型交集
ts
type Bird = {
  fly: () => void
}
type Fish = {
  swim: () => void
}

type Animal = Bird & Fish
// Animal: {
//   fly: () => void;
//   swim: () => void;
// }

枚举

枚举表示一组常量集合,通过 enum 关键字定义

ts
enum FORM_ITEMS {
  INPUT: 'input',
  SELECT: 'select'
}

数字枚举

当定义数字枚举类型时, TypeScript 默认对成员进行自动递增,若初始项没有赋值,则默认由 0 开始

ts
// 默认由 0 开始递增
enum Queues {
  FIRST,
  SECOND
}
console.log(Queues.FIRST) // 0
console.log(Queues.SECOND) // 1

// 按序递增
enum Queues {
  FIRST = 1,
  SECOND,
  THIRD = 5,
  FOURTH,
  FIFTH
}
console.log(Queues.FIRST) // 1
console.log(Queues.SECOND) // 2
console.log(Queues.THIRD) // 5
console.log(Queues.FOURTH) // 6
console.log(Queues.FIFTH) // 7

反向映射

数字枚举成员还可以通过枚举值获取对应的枚举名称,称为 反向映射

ts
enum Queues {
  FIRST,
  SECOND
}
console.log(Queues[0]) // FIRST
console.log(Queues[1]) // SECOND

进阶

随着 ECMAScript 的发展,TypeScript 中针对 ES6 Class 的特性已经逐步落地并于主流浏览器/平台上得到支持。

继承

  • 通过 extends 关键字派生子类实现继承

  • 通过 super 关键字执行基类构造函数、访问基类的属性或方法

ts
const enum SEX {
  UNKNOWN,
  MAN,
  WOMAN
}

class Person {
  name: string
  constructor(name: string) {
    this.name = name
  }
  introduce() {
    console.log(`Hello, my name is ${this.name}.`)
  }
}

class Man extends Person {
  gender = SEX.MAN
  constructor(name: string) {
    super(name)
  }
}

const man = new Man('donggua')
console.log(man) // Man { name: 'donggua', gender: 1 }
man.introduce() // Hello, my name is donggua.

存取器

在类中可以通过 getterssetters 拦截对象成员的存取行为

ts
class Person {
  _name: string
  constructor(name: string) {
    this._name = name
  }
  get name() {
    return this._name
  }
  set name(newName: string) {
    this._name = newName
  }
}

const man = new Person('donggua')
man.name = 'donggua_nor'
man.name // donggua_nor

TIP

仅设置了 get 而没有 set 的存取器将被推断为 readonly ,以告知用户该属性不应该被改变

ts
class Person {
  _name: string
  constructor(name: string) {
    this._name = name
  }
  get name() {
    return this._name
  }
}

const man = new Person('donggua')
man.name = 'donggua_nor'
// Cannot assign to 'name' because it is a read-only property

属性修饰符

TypeScript 提供了几种语义化的修饰符,用以描述类中各种属性:

  • readonly 只读属性
ts
class Person {
  readonly name: string
  constructor(name: string) {
    this.name = name
  }
}

const man = new Person('donggua')
man.name = 'donggua_nor'
// Cannot assign to 'name' because it is a read-only property
  • public 表示公有的访问修饰符,可以自由访问类中的成员
  • private 表示私有的访问修饰符,只能在类内部使用
  • protected 表示受保护的访问修饰符,只能在基类及其派生类内部使用
ts
class Person {
  public name: string
  private age: number
  protected address: string
  constructor(name: string, age: number, address: string) {
    this.name = name
    this.age = age
    this.address = address
  }
}

class Man extends Person {
  constructor(name: string, age: number, address: string) {
    super(name, age, address)
  }
  getAge() {
    console.log(this.age)
    // Property 'age' is private and only accessible within class 'Person'
  }
  getAddress() {
    return this.address
  }
}

const man = new Man('donggua', 26, 'guangzhou')
console.log(man.name) // donggua
man.age
// Property 'age' is private and only accessible within class 'Person'
man.address
// Property 'address' is protected and only accessible within class 'Person'
// and its subclasses

TIP

  • 不同于 C# 必须明确使用 public 指定成员是公开的,TypeScript 默认成员为 public 属性
  • ECMAScript 新提案 中对于私有属性/方法是使用 # 修饰符
ts
class Person {
  #name: string
  constructor(name: string) {
    this.name = name
  }
}
const man = new Person('donggua')
man.name
// Property '#name' is not accessible outside class 'Person'
// because it has a private identifier
  • static 静态属性与静态方法

不同于实例属性/方法,静态属性/方法不会被实例所继承,而必须通过类来使用

ts
class SingleInstance {
  static instance: SingleInstance
  private constructor(public name: string) {}
  static getInstance(name: string) {
    if (!this.instance) {
      this.instance = new SingleInstance(name)
    }
    return this.instance
  }
}

const instance1 = SingleInstance.getInstance('instance1')
const instance2 = SingleInstance.getInstance('instance2')
console.log(instance1 === instance2) // true

抽象类

除了上述关键字,TypeScript 还提供了 abstract 关键字用于定义抽象类以及抽象类内部的抽象方法。

ts
abstract class Person {
  constructor(public name: string) {}
  abstract introduce(): void
}

其中,抽象类应作为基类使用,不可被实例化。抽象类中的抽象方法不包含具体实现并且必须由派生类实现:

ts
abstract class Person {
  constructor(public name: string) {}
  abstract introduce(): void
}

class Man extends Person {
  constructor(name: string) {
    super(name)
  }
  introduce() {
    console.log(`Hello, my name is ${this.name}.`)
  }
}

const err = new Person() // Cannot create an instance of an abstract class
const man = new Man('donggua')

类实现接口

类同 JavaC# ,TypeScript 支持类继承一个或多个接口以约束类的行为,即类必须拥有接口中对应的属性和方法,通过 implemenets 关键字实现

ts
interface Person {
  name: string
  introduce: () => void
}

class Man implements Person {
  constructor(public name: string) {}
  introduce() {
    console.log(`Hello, my name is ${this.name}.`)
  }
}

WARNING

类实现接口时,仅支持实例部分属性/方法,而不允许接口定义其静态属性/方法

ts
interface Person {
  new (name: string): void
}

class Man implements Person {
  constructor(public name: string) {}
}
// Class 'Man' incorrectly implements interface 'Person'.
// Type 'Man' provides no match for the signature 'new (name: string): void'

TIP

类也可以实现类型别名,但接口更为贴合类

ts
type Person = {
  name: string
  introduce: () => void
}

class Man implements Person {
  constructor(public name: string) {}
  introduce() {
    console.log(`Hello, my name is ${this.name}.`)
  }
}

接口继承类

在 TypeScript 中支持接口继承类,接口继承类后,将拥有类中所有的属性与方法:

ts
class Person {
  constructor(public name: string, public age: number) {}
}
interface Man extends Person {
  address: string
}

const donggua: Man = {
  name: 'donggua',
  age: 26,
  address: 'guangzhou'
}

泛型

泛型就是将原本具体的类型作为参数声明,在使用或调用时再指定为具体的类型,即 参数化类型。通过泛型,可以协助我们定义可复用的方法、接口和类。

泛型变量

假设我们需要定义一个函数,该函数的作用是返回任何传入的值,那么我们自然会想到使用 any

ts
function identity(arg: any): any {
  return arg
}

虽然结果是符合预期的,但使用 any 将失去类型检查,违背使用 TypeScript 的初衷。即使场景下明确不需要类型检查,但项目中开启了 noImplicitAny 配置,导致我们无法使用 any

此时泛型就派上了用场:我们可以使用 <> 定义一个参数变量 Type 用于捕获实际传入的类型,通过该参数变量,我们就可以指定实参和返回值为对应的类型

ts
function identity<T>(arg: T): T {
  return arg
}

console.log(identity<string>('donggua')) // 'donggua'

上述代码意为, identity 函数接收 类型参数 T 和参数 arg ,参数 arg 和函数返回值类型是 T 。当传入 string 类型的参数时, T 的具体类型就是 string

各类泛型定义

  • 箭头函数和对象字面量

以上述例子为例,我们可以将其改造为箭头函数形式

ts
const identity: <T>(arg: T) => T = arg => arg

为方便理解,可以把上述代码拆解为:

ts
type GenericFn = <T>(arg: T) => T
let identity: GenericFn
identity = arg => arg // identity = (arg) => { return arg }

对于箭头函数的泛型定义,我们还可以使用对象字面量的形式书写

ts
// type GenericFn = <T>(arg: T) => T
type GenericFn = { <T>(arg: T): T }
  • 泛型接口

结合上述类型别名和对象字面量的泛型定义,我们不难想到泛型接口的定义形式:

ts
interface GenericFn {
  <T>(arg: T): T
}

为了清晰的表明具体的类型参数,一般将类型参数提取出来,以表明泛型参数为整个接口的参数

ts
interface GenericFn<T> {
  (arg: T): T
}
  • 泛型类

泛型类和泛型接口实现相似,但始终应注意的是,类的静态属性/方法亦不能使用泛型类型

ts
class GenericNumber<T> {
  zeroValue: T
  add: (x: T, y: T) => T
}

let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = function (x, y) {
  return x + y
}
  • 类的构造函数

当需要对类的构造函数进行类型声明时,应采用 new 关键字结合 ()

ts
interface Ctor<T> {
  new (): T
}
function createInstance<T>(ctor: Ctor<T>): T {
  return new ctor()
}

class Person {
  name: string = 'donggua'
}

const man = createInstance(Person)
console.log(man) // Person { name: 'donggua' }

类型收窄

除了上下文的类型推断,TypeScript 还提供 类型收窄 机制,可协助编辑器将类型推断为更精确的类型范围,即将宽类型约束为窄类型。

类型保护

类型保护通常使用 JavaScript 代码逻辑判断进行类型收窄:

  • typeof 判断原始数据类型
  • boolean 类型转换
  • switch===!== 等值判断
  • in 判断对象属性是否存在
  • instanceof 判断构造函数实例
  • ifwhile 等控制流语句

类型断言

类型断言使用 as 关键字声明指定一个具体的类型

ts
type Bird = {
  fly: () => void
}
type Fish = {
  swim: () => void
}

function behavior(pet: Fish | Bird) {
  if ((pet as Fish).swim) {
    ;(pet as Fish).swim() // pet: Fish
  } else {
    ;(pet as Bird).fly() // pet: Bird
  }
}

类型谓词

类型谓词采用 parameterName is Type 形式进行类型收窄:

ts
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined
}

function behavior(pet: Fish | Bird) {
  if (isFish(pet)) {
    pet.swim() // pet: Fish
  } else {
    pet.fly() // pet: Bird
  }
}

isFish 函数以类型谓词 pet is Fish 代替 boolean 作为函数返回值,借助 isFish 函数便可将 pet 收窄为对应类型。

声明合并

声明合并 是指 TypeScript 编译器会针对函数、接口或类等的同名声明进行合并,并拥有所有合并的声明的特性

Java 之类的语言中,最熟悉的声明合并就是 函数重载

ts
// 最为常见的接口合并
interface Person {
  name: string
  age: number
}
interface Person {
  gender: number
}
const person: Person = {
  name: 'donggua',
  age: 26,
  gender: 1
}

// 函数重载
function add(a: number, b: number): number
function add(a: string, b: string): string
function add(a: number | string, b: number | string): number | string {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b
  }
  return `${a}${b}`
}

TypeScript 中重载的注意事项

  • 声明方式为连续多个声明后紧跟具体实现函数,否则将报错
ts
function add(a: number, b: number): number
function add(a: number | string, b: number | string): number | string {
  return `${a}${b}`
}
function add(a: string, b: string): string
// Function implementation is missing or not immediately following the declaration.
// 函数声明缺少或没有紧随一个实现函数
  • 最终实现必须兼容已有的构造声明
ts
function add(a: number, b: number): number
// This overload signature is not compatible with its implementation signature.
function add(a: string, b: string): string {
  return a + b
}

条件类型

条件类型 类似于 JavaScript 中的三元表达式:

ts
type IsBoolean<T> = T extends boolean ? true : false
type IsArray<T> = T extends { length: number } ? true : false

type Res1 = IsBoolean<string> // false
type Res2 = IsBoolean<true> // true
type Res3 = IsBoolean<true> // false
type Res4 = IsArray<[1, 2]> // true

extends

在条件类型中, extends 右侧紧随联合类型,意为将类型收窄为该联合类型范围内,称为 类型约束

ts
type GetArrayItem<T> = T extends any[] ? T[number] : T
type Item = GetArrayItem<string[]>
// Item: string
type Arg = GetArrayItem<number>
// Arg:number

GetArrayItem<T> 用于获取数组元素的类型, T extends any[] 意为约束传入类型为数组,当条件成立时借用索引类型 T[number] 返回数组元素的类型,否则返回传入的类型。

infer

infer 关键字在条件类型中声明占位变量,起到延迟推断获取正确类型的作用。

ts
type GetArrayItem<T> = T extends Array[infer Item] ? Item : T
type Item = GetArrayItem<string[]>
// Item: string
type Arg = GetArrayItem<number>
// Arg:number

借助 infer 修改了 GetArrayItem<T> 的实现,声明占位变量 Item ,当传入类型满足对应的类型数组约束时,直接返回推断出的类型 Item ,否则返回传入的类型。

再以 ReturnType<T> 为例,用于获取函数返回类型:

ts
type ReturnType<T> = T extends (...args: any) => infer R ? R : any

const add = (a: number, b: number): number => a + b

type Result = ReturnType<typeof add>
// Result: number
  • 声明泛型变量 T 表示一个函数类型
  • 声明占位变量 R,此时并不确定函数具体返回类型
  • T 类型为函数类型,则根据函数类型上下文推导出 R 具体类型并返回,否则则返回 any 类型
  • 在上述例子中,add 即为返回 number 类型的函数,由此推断出 Rnumber

分布式条件类型

在条件类型中,对联合类型应用 extends 时,会遍历联合类型成员并一一应用该条件类型:

ts
type FilterStr<T> = T extends string ? never : T
type Union = string | number | boolean
type Result = FilterStr<Union>
// Result: number | boolean

FilterStr<T> 用于过滤掉 string 类型获取新的联合类型,其中传入类型 T 为联合类型,即 string | number | boolean extends string 将对联合类型所有成员进行分发运算:

ts
string | number | boolean extends string
=> string extends string   // true
=> number extends string   // false
=> boolean extends string  // false

最终结果即为: never | number | boolean ,并根据联合类型中的 never 特性得: number | boolean

TIP

通过 [] 包裹 extends 关键词每一部分可规避应用分布式条件类型

ts
type FilterStr<T> = [T] extends [string] ? never : T
type Union = string | number | boolean
type Result = FilterStr<Union>
// Result: string | number | boolean

typeof

typeof 操作符用于在获取变量或属性的类型,多用于获取复杂数据类型,或配合其他操作符使用

ts
// 对原始类型使用时等同于 JavaScript 中的 typeof,返回对应类型,但并没有什么必要
type name: string = 'donggua'
type Base = typeof name
// Base: string

// 对对象使用时,将获取对象完整的属性类型
const person = { name: "donggua", age: "26" }
type Obj = typeof person;
// Obj: { name: string; age: number }

// 对枚举类型使用形似于对象
enum TYPES {
  INPUT,
  SELECT,
}
type Enum = typeof TYPES
// Enum: { INPUT: number; SELECT: number }

// 对函数使用
function sum(a: number, b: number): number {
  return a + b
}
type Func = typeof sum
// Func: (a: number, b: number) => number

never

never 关键字除了应用于函数声明,还有额外的特性:一个联合类型中存在 never ,其实际的联合类型并不会包含 never

ts
// 定义
type test = 'name' | 'age' | never
// 实际
type test = 'name' | 'age'

keyof

keyof 操作符用于获取对象所有属性键的字面量组合而成的联合类型,类似于 JavaScript 中的 Object.keys()

ts
type Person = {
  name: string
  age: number
}
type Result = keyof Person
// Result: 'name' | 'age'
  • 需要注意的是,对于 number 类型的索引签名,将视为 string | number 联合类型,因为 JavaScript 中对象属性键会被强制转换为字符串
ts
type Mapish = {
  [key: number]: string
}
type Result = keyof Arrayish
// Result: 'string' | 'number'

const obj: Mapish = {}
obj[1] = 'donggua' // 等同于 obj['1'] = 'donggua'

in

in 操作符右侧跟随一个联合类型,表示逐一遍历该联合类型的所有字面量,类似于 JavaScript 中的 for...in ,通常结合 keyof 用以创建索引签名的映射类型

ts
type Readonly<T> = {
  readonly [K in keyof T]: T[K]
}
type Person = {
  name: string
  age: number
}

type Result = Readonly<Person>
// Result:{
//   readonly name: string;
//   readonly age: number;
// }
  • 定义 Readonly 工具函数,接收一个泛型参数 T
  • keyof T 获取 T 的联合类型,在此结果为 'name' | 'age'
  • 使用 in 遍历 'name' | 'age' 并将每次的取值赋值给变量 K
  • readonly 关键字将对象中的属性转换为只读属性,对应值为 T[K]

拓展

装饰器

命名空间

tsconfig.json

TIP

本节内容由好友 @maomao1996 整理,原出处 mm-notes

tsconfig.json | Docs

compilerOptions

compilerOptions 是用于配置 TypeScript 编译器的选项

这里列举的是通过 tsc --init 生成的默认配置(tsc 的版本为 5.0.3

json
{
  /* 项目相关 */
  "incremental": true,                              /* 增量编译,允许将编译结果保存到 .tsbuildinfo 文件中,以优化后续的编译速度 */
  "composite": true,                                /* 组合项目,允许将多个项目组合成一个项目,以优化编译速度 */
  "tsBuildInfoFile": "./",                          /* 指定 .tsbuildinfo 文件的输出目录 */
  "disableSourceOfProjectReferenceRedirect": true,  /* 禁用项目引用的源文件重定向 */
  "disableSolutionSearching": true,                 /* 禁用解决方案搜索 */
  "disableReferencedProjectLoad": true,             /* 禁用引用的项目加载 */

  /* 语言和环境 */
  "target": "esnext",                               /* 编译目标,可选值:es3、es5、es6、es2015、es2016、es2017、es2018、es2019、es2020、esnext */
  "lib": ["dom", "dom.iterable", "esnext"],         /* 编译时需要引入的库文件 */
  "jsx": "preserve",                                /* 控制 JSX 在 JavaScript 文件中的输出方式,可选值:react、react-jsx、react-jsxdev、react-native、preserve */
  "experimentalDecorators": true,                   /* 启用实验性的装饰器语法 */
  "emitDecoratorMetadata": true,                    /* 启用装饰器元数据 */
  "jsxFactory": "React.createElement",              /* 指定 JSX 的工厂函数 */
  "jsxFragmentFactory": "React.Fragment",           /* 指定 JSX 的片段工厂函数 */
  "jsxImportSource": "react",                       /* 指定 JSX 的导入源 */
  "reactNamespace": "React",                        /* 指定 React 的命名空间 */
  "noLib": true,                                    /* 不引入默认的库文件 */
  "useDefineForClassFields": true,                  /* 使用 ECMAScript 中的类字段定义语法 */
  "moduleDetection": "auto",                        /* 模块检测,可选值:auto、legacy、force */

  /* 模块解析选项 */
  "module": "commonjs",                             /* 模块解析策略,可选值:none、commonjs、amd、system、umd、es2015、esnext */
  "rootDir": "./",                                  /* 指定项目根目录 */
  "moduleResolution": "node",                       /* 模块解析策略,可选值:node、classic */
  "baseUrl": "./",                                  /* 指定模块解析的基本目录 */
  "paths": {},                                      /* 指定模块名到基于 baseUrl 的路径映射 */
  "rootDirs": [],                                   /* 指定多个根目录 */
  "typeRoots": [],                                  /* 指定类型声明文件的查找目录 */
  "types": [],                                      /* 指定需要引入的类型声明文件 */
  "allowUmdGlobalAccess": true,                     /* 允许 UMD 模块访问全局变量 */
  "moduleSuffixes": [],                             /* 指定模块后缀名 */
  "allowImportingTsExtensions": true,               /* 允许导入 .ts 文件 */
  "resolvePackageJsonExports": true,                /* 解析 package.json 中的 exports 字段 */
  "resolvePackageJsonImports": true,                /* 解析 package.json 中的 imports 字段 */
  "customConditions": [],                           /* 指定自定义的条件 */
  "resolveJsonModule": true,                        /* 解析 JSON 模块 */
  "allowArbitraryExtensions": true,                 /* 允许导入任意扩展名的文件 */
  "noResolve": true,                                /* 不解析模块 */
  "allowJs": true,                                  /* 允许编译 JavaScript 文件 */
  "checkJs": true,                                  /* 允许检查 JavaScript 文件 */
  "maxNodeModuleJsDepth": 1,                        /* 指定在 node_modules 中查找 JavaScript 文件的深度 */

  /* 源码映射选项 */
  "declaration": true,                              /* 生成声明文件 */
  "declarationMap": true,                           /* 生成声明文件映射文件 */
  "emitDeclarationOnly": true,                      /* 只生成声明文件 */
  "sourceMap": true,                                /* 生成源码映射文件 */
  "inlineSourceMap": true,                          /* 将源码映射文件内联到输出文件中 */
  "outFile": "./",                                  /* 将输出文件合并为一个文件 */
  "outDir": "./",                                   /* 指定输出目录 */
  "removeComments": true,                           /* 删除注释 */
  "noEmit": true,                                   /* 不生成输出文件 */
  "importHelpers": true,                            /* 从 tslib 导入辅助函数 */
  "importsNotUsedAsValues": "remove",               /* 删除未使用的导入 */
  "downlevelIteration": true,                       /* 降级迭代器 */
  "sourceRoot": "",                                 /* 指定源码根目录 */
  "mapRoot": "",                                    /* 指定源码映射文件的根目录 */
  "inlineSources": true,                            /* 将源码内联到源码映射文件中 */
  "emitBOM": true,                                  /* 在输出文件中添加 BOM */
  "newLine": "lf",                                  /* 指定换行符,可选值:crlf、lf */
  "stripInternal": true,                            /* 删除内部注释 */
  "noEmitHelpers": true,                            /* 不生成辅助函数 */
  "noEmitOnError": true,                            /* 编译错误时不生成输出文件 */
  "preserveConstEnums": true,                       /* 保留 const 枚举 */
  "declarationDir": "./",                           /* 指定声明文件的输出目录 */
  "preserveValueImports": true,                     /* 保留值导入 */
  "isolatedModules": true,                          /* 禁用一些不支持的特性 */
  "verbatimModuleSyntax": true,                     /* 禁用模块解析 */
  "allowSyntheticDefaultImports": true,             /* 允许从没有默认导出的模块中导入 */
  "esModuleInterop": true,                          /* 允许从 CommonJS 模块中导入 */
  "preserveSymlinks": true,                         /* 保留符号链接 */
  "forceConsistentCasingInFileNames": true,         /* 强制文件名大小写一致 */

  /* 类型检查选项 */
  "strict": true,                                   /* 启用所有严格类型检查选项 */
  "noImplicitAny": true,                            /* 禁止隐式的 any 类型 */
  "strictNullChecks": true,                         /* 启用严格的空值检查 */
  "strictFunctionTypes": true,                      /* 启用严格的函数类型检查 */
  "strictBindCallApply": true,                      /* 启用严格的 bind/call/apply 检查 */
  "strictPropertyInitialization": true,             /* 启用严格的属性初始化检查 */
  "noImplicitThis": true,                           /* 禁止 this 表达式隐式的 any 类型 */
  "useUnknownInCatchVariables": true,               /* 使用 unknown 替代 catch 变量的 any 类型 */
  "alwaysStrict": true,                             /* 在每个源文件中添加 'use strict' */
  "noUnusedLocals": true,                           /* 禁止未使用的局部变量 */
  "noUnusedParameters": true,                       /* 禁止未使用的参数 */
  "exactOptionalPropertyTypes": true,               /* 启用精确的可选属性类型检查 */
  "noImplicitReturns": true,                        /* 禁止函数中的隐式返回 */
  "noFallthroughCasesInSwitch": true,               /* 禁止 switch 语句的落空 case */
  "noUncheckedIndexedAccess": true,                 /* 禁止未检查的索引访问 */
  "noImplicitOverride": true,                       /* 禁止重写类成员的隐式声明 */
  "noPropertyAccessFromIndexSignature": true,       /* 禁止从索引签名中访问属性 */
  "allowUnusedLabels": true,                        /* 允许未使用的标签 */
  "allowUnreachableCode": true,                     /* 允许不可达代码 */

  /* 附加检查 */
  "skipDefaultLibCheck": true,                      /* 跳过对默认库的类型检查 */
  "skipLibCheck": true,                             /* 跳过对声明文件的类型检查 */

  /* 输出格式 */
  "noErrorTruncation": true,                        /* 禁止错误信息截断 */
  "preserveWatchOutput": true,                      /* 保留 watch 输出 */
  "pretty": true                                    /* 使用漂亮的输出 */
}

files

files 是用于指定 TypeScript 编译器应该编译哪些文件(支持相对路径、绝对路径)

  • Default: false
json
{
  "files": ["core.ts", "types.ts", "utils.ts", "maomao.ts"]
}

WARNING

当指定的文件或文件夹不存在时,会提示错误

include

include 是用于指定 TypeScript 编译器应该编译哪些文件(支持相对路径、绝对路径和 glob 模式)

  • Default: []
json
{
  "include": ["src/**/*", "tests/**/*"]
}

filesinclude

  • files
    • 不会排除 exclude 中指定的文件或目录
    • 支持相对路径、绝对路径
    • 路径必须指向文件,不能指向目录
  • include
    • 会排除 exclude 中指定的文件或目录
    • 支持相对路径、绝对路径和 glob 模式
    • 路径可以指向文件,也可以指向目录

exclude

exclude 是用于指定 TypeScript 编译器应该忽略哪些文件,从而不对这些文件进行编译

  • Default: ["node_modules", "bower_components", "jspm_packages", "outDir"]
json
{
  "exclude": ["node_modules", "maomao"]
}

extends

extends 是用于指定父级配置文件的路径,从而继承父级配置文件中的编译选项

  • Default: false
json
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist"
  }
}

references

项目引用是 TypeScript 3.0 新增的特性,用于将多个 TypeScript 项目组合在一起进行编译

references 是用于指定项目引用的路径,从而引用项目

  • Default: false
json
{
  "compilerOptions": {
    "outDir": "./dist"
  },
  "references": [{ "path": "./tsconfig.base.json" }]
}

Last updated: