TypeScript
TypeScript 笔记,基于 官方文档 与 @wangtunan 、@maomao 的慷慨分享
基础
原始类型
string
number
boolean
symbol
bigint
null
undefined
null 与 undefined
- 非空断言
非空断言采用 !.
操作符,用以移除 null
、 undefined
类型,类似于 JavaScript 可选链操作符 ?.
function liveDangerously(x?: number | null) {
console.log(x!.toFixed())
}
- strictNullChecks
strictNullChecks
开启严格空值检查模式
// tsconfig.json
{
"strictNullChecks": true
}
该模式下, null
、 undefined
只允许被分配给自己或 any
类型的变量
const a: null = null
const b: undefined = undefined
const c: any = null
const err: number = null // Type 'null' is not assignable to type 'number'
访问一个可能是 null
、 undefined
类型的变量属性或方法时,需先进行类型收窄
function printLength(value?: string | null) {
if (typeof value === 'string') {
console.log(value.length)
}
}
任意值
any
是一个特殊的类型,当一个值是 any
类型的时候, TypeScript 将不会对其进行类型检查
// 如同写 js,你可以任意操作你的变量,TypeScript 并不会抛出相关的提示
let free: any = 1
free = { name: 'donggua' }
free.log()
free = 'any'
noImplicitAny
noImplicitAny
严格检查类型,不允许任何隐式 any
类型
// tsconfig.json
{
"noImplicitAny": true
}
function fn(s) {
// Parameter 's' implicitly has an 'any' type
console.log(s.subtr(3))
}
WARNING
无论是开发者指定或是由 TypeScript 隐式推断出的 any
类型,都会导致 TypeScript 失去准确的类型推断能力。可能会导致遗漏一些运行时错误,违背使用 TypeScript 的初衷。
Unknown
unknown
用于描述一个我们还不知道其类型的变量
let notSure: unknown = 4
notSure = 'maybe a string instead'
// OK, definitely a boolean
notSure = false
unknown VS any
相比于 any
不会对变量进行任何检查,对于 unknown
类型的变量在执行大多数操作时必须进行相应的检查,因此 unknown
类型相对更加严格
字面量
除了常见的类型,还可以将类型声明为具体的数字或者字符串,常用于 联合类型
const demo: 'demo' = 'demo'
// 更常用的联合类型
type Alignment = 'left' | 'right' | 'center'
对象
定义对象类型,可以罗列属性和对应的类型
const obj: { name: string; job: string } = {
name: 'donggua',
job: 'fe'
}
在 JavaScript 中访问对象还可以使用方括号 []
作为属性访问器,TypeScript 也提供了对应的 索引访问类型。
即通过 []
进行索引签名访问,并以此创建 映射类型:
const obj: { [key: string]: string } = {
name: 'donggua',
job: 'fe'
}
函数
TypeScript 允许指定函数的参数类型和返回类型
function sum(a: number, b: number): number {
return a + b
}
空值
对于没有返回值的函数,用 void
进行声明注解
function log(): void {
console.log('TypeScript is Cool!')
}
匿名函数
不同于函数声明,TypeScript 会根据 上下文推断 为匿名函数指定正确的类型
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
类型表示的是那些永不存在的值的类型,更多的用于表示函数无法达到终点
function errorHandler(message: string): never {
throw new Error(message)
}
function infiniteLoop(): never {
while (true) {}
}
数组与元组
- 数组类型声明有
类型[]
以及 泛型 两种形式
const queues: number[] = [1, 2, 3]
const stack: Array<number> = [1, 2, 3]
- 元组相当于固定长度的数组,并且已知数组每项对应的的类型
对元祖类型的数据进行 越界访问 或 分配错误的类型值 时,TypeScript 将报错提示
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
type ID = number
type Person = {
name: string
age: number
}
- 接口是指定对象类型命名的另一种形式
interface Person {
name: string
age: number
}
type VS interface
- 二者都可以用来声明对象或函数签名,仅语法不同
// 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
// 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
不行
type str = string
type Union = string | number
type tuple = [string, number]
- 类可以实现接口或类型别名,但不可实现联合类型的类型别名
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
interface
支持 声明合并
TIP
类似 let
、 const
的选择,一般情况下建议使用 interface
,在不支持的情况下再使用 type
类型别名
类型推断与类型注解
- 类型注解:显式指定变量的类型
- 类型推断:由 TypeScript 根据上下文内容自动推断出变量类型
let nickname: string = 'donggua'
let job = 'FE' // TypeScript 自动推断为 job: string
TIP
- 在为变量赋值明确的值时,建议尽量使用 类型注解 的方式
- 对于函数返回值,始终显示指明返回类型是个更好的习惯
联合类型与交叉类型
- 联合类型是由两个或者更多类型组成的类型,并用
|
连接,表示值可能是这些类型中的任意一个
function print(value: number | string): void {
console.log(value)
}
- 交叉类型是由多个类型的成员合并,用
&
连接,表示取所有成员的类型交集
type Bird = {
fly: () => void
}
type Fish = {
swim: () => void
}
type Animal = Bird & Fish
// Animal: {
// fly: () => void;
// swim: () => void;
// }
枚举
枚举表示一组常量集合,通过 enum
关键字定义
enum FORM_ITEMS {
INPUT: 'input',
SELECT: 'select'
}
数字枚举
当定义数字枚举类型时, TypeScript 默认对成员进行自动递增,若初始项没有赋值,则默认由 0
开始
// 默认由 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
反向映射
数字枚举成员还可以通过枚举值获取对应的枚举名称,称为 反向映射
enum Queues {
FIRST,
SECOND
}
console.log(Queues[0]) // FIRST
console.log(Queues[1]) // SECOND
进阶
类
随着
ECMAScript
的发展,TypeScript 中针对 ES6 Class 的特性已经逐步落地并于主流浏览器/平台上得到支持。
继承
通过
extends
关键字派生子类实现继承通过
super
关键字执行基类构造函数、访问基类的属性或方法
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.
存取器
在类中可以通过 getters
、 setters
拦截对象成员的存取行为
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
,以告知用户该属性不应该被改变
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
只读属性
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
表示受保护的访问修饰符,只能在基类及其派生类内部使用
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
新提案 中对于私有属性/方法是使用#
修饰符
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
静态属性与静态方法
不同于实例属性/方法,静态属性/方法不会被实例所继承,而必须通过类来使用
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
关键字用于定义抽象类以及抽象类内部的抽象方法。
abstract class Person {
constructor(public name: string) {}
abstract introduce(): void
}
其中,抽象类应作为基类使用,不可被实例化。抽象类中的抽象方法不包含具体实现并且必须由派生类实现:
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')
类实现接口
类同 Java
、 C#
,TypeScript 支持类继承一个或多个接口以约束类的行为,即类必须拥有接口中对应的属性和方法,通过 implemenets
关键字实现
interface Person {
name: string
introduce: () => void
}
class Man implements Person {
constructor(public name: string) {}
introduce() {
console.log(`Hello, my name is ${this.name}.`)
}
}
WARNING
类实现接口时,仅支持实例部分属性/方法,而不允许接口定义其静态属性/方法
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
类也可以实现类型别名,但接口更为贴合类
type Person = {
name: string
introduce: () => void
}
class Man implements Person {
constructor(public name: string) {}
introduce() {
console.log(`Hello, my name is ${this.name}.`)
}
}
接口继承类
在 TypeScript 中支持接口继承类,接口继承类后,将拥有类中所有的属性与方法:
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
function identity(arg: any): any {
return arg
}
虽然结果是符合预期的,但使用 any
将失去类型检查,违背使用 TypeScript 的初衷。即使场景下明确不需要类型检查,但项目中开启了 noImplicitAny
配置,导致我们无法使用 any
。
此时泛型就派上了用场:我们可以使用 <>
定义一个参数变量 Type
用于捕获实际传入的类型,通过该参数变量,我们就可以指定实参和返回值为对应的类型
function identity<T>(arg: T): T {
return arg
}
console.log(identity<string>('donggua')) // 'donggua'
上述代码意为, identity
函数接收 类型参数 T
和参数 arg
,参数 arg
和函数返回值类型是 T
。当传入 string
类型的参数时, T
的具体类型就是 string
。
各类泛型定义
- 箭头函数和对象字面量
以上述例子为例,我们可以将其改造为箭头函数形式
const identity: <T>(arg: T) => T = arg => arg
为方便理解,可以把上述代码拆解为:
type GenericFn = <T>(arg: T) => T
let identity: GenericFn
identity = arg => arg // identity = (arg) => { return arg }
对于箭头函数的泛型定义,我们还可以使用对象字面量的形式书写
// type GenericFn = <T>(arg: T) => T
type GenericFn = { <T>(arg: T): T }
- 泛型接口
结合上述类型别名和对象字面量的泛型定义,我们不难想到泛型接口的定义形式:
interface GenericFn {
<T>(arg: T): T
}
为了清晰的表明具体的类型参数,一般将类型参数提取出来,以表明泛型参数为整个接口的参数
interface GenericFn<T> {
(arg: T): T
}
- 泛型类
泛型类和泛型接口实现相似,但始终应注意的是,类的静态属性/方法亦不能使用泛型类型
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
关键字结合 ()
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
判断构造函数实例if
、while
等控制流语句
类型断言
类型断言使用 as
关键字声明指定一个具体的类型
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
形式进行类型收窄:
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
之类的语言中,最熟悉的声明合并就是 函数重载
// 最为常见的接口合并
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 中重载的注意事项
- 声明方式为连续多个声明后紧跟具体实现函数,否则将报错
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.
// 函数声明缺少或没有紧随一个实现函数
- 最终实现必须兼容已有的构造声明
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 中的三元表达式:
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
右侧紧随联合类型,意为将类型收窄为该联合类型范围内,称为 类型约束
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
关键字在条件类型中声明占位变量,起到延迟推断获取正确类型的作用。
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>
为例,用于获取函数返回类型:
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
类型的函数,由此推断出R
为number
分布式条件类型
在条件类型中,对联合类型应用 extends
时,会遍历联合类型成员并一一应用该条件类型:
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
将对联合类型所有成员进行分发运算:
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
关键词每一部分可规避应用分布式条件类型
type FilterStr<T> = [T] extends [string] ? never : T
type Union = string | number | boolean
type Result = FilterStr<Union>
// Result: string | number | boolean
typeof
typeof
操作符用于在获取变量或属性的类型,多用于获取复杂数据类型,或配合其他操作符使用
// 对原始类型使用时等同于 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
// 定义
type test = 'name' | 'age' | never
// 实际
type test = 'name' | 'age'
keyof
keyof
操作符用于获取对象所有属性键的字面量组合而成的联合类型,类似于 JavaScript 中的 Object.keys()
type Person = {
name: string
age: number
}
type Result = keyof Person
// Result: 'name' | 'age'
- 需要注意的是,对于
number
类型的索引签名,将视为string | number
联合类型,因为 JavaScript 中对象属性键会被强制转换为字符串
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
用以创建索引签名的映射类型
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
compilerOptions
compilerOptions
是用于配置 TypeScript 编译器的选项
这里列举的是通过
tsc --init
生成的默认配置(tsc
的版本为5.0.3
)
{
/* 项目相关 */
"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
{
"files": ["core.ts", "types.ts", "utils.ts", "maomao.ts"]
}
WARNING
当指定的文件或文件夹不存在时,会提示错误
include
include
是用于指定 TypeScript 编译器应该编译哪些文件(支持相对路径、绝对路径和 glob
模式)
- Default:
[]
{
"include": ["src/**/*", "tests/**/*"]
}
files
和 include
files
- 不会排除
exclude
中指定的文件或目录 - 支持相对路径、绝对路径
- 路径必须指向文件,不能指向目录
- 不会排除
include
- 会排除
exclude
中指定的文件或目录 - 支持相对路径、绝对路径和
glob
模式 - 路径可以指向文件,也可以指向目录
- 会排除
exclude
exclude
是用于指定 TypeScript 编译器应该忽略哪些文件,从而不对这些文件进行编译
- Default:
["node_modules", "bower_components", "jspm_packages", "outDir"]
{
"exclude": ["node_modules", "maomao"]
}
extends
extends
是用于指定父级配置文件的路径,从而继承父级配置文件中的编译选项
- Default:
false
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist"
}
}
references
项目引用是 TypeScript 3.0 新增的特性,用于将多个 TypeScript 项目组合在一起进行编译
references
是用于指定项目引用的路径,从而引用项目
- Default:
false
{
"compilerOptions": {
"outDir": "./dist"
},
"references": [{ "path": "./tsconfig.base.json" }]
}