基本类型

JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。
原始数据类型包括布尔值、数值、字符串、null、undefined 以及 ES6 中的新类型 Symbol。
对象类型包括数组、函数以及普通对象。
TypeScript 在这些类型的基础上衍生出元组、枚举、any、void、never 等。

TypeScript 的一个比较重要的功能就是类型检查,如果类型不符就会报错。下面对一些简单基本类型的检查进行列举。

布尔值

1
let isDone: boolean = false

注意,使用构造函数 Boolean 创造的对象不是布尔值:

1
let createdByNewBoolean: boolean = new Boolean(1) // 报错

事实上 new Boolean() 返回的是一个 Boolean 对象:

1
let createdByNewBoolean: Boolean = new Boolean(1)

直接调用 Boolean 也可以返回一个 boolean 类型:

1
let createdByBoolean: boolean = Boolean(1)

其他基本类型(除了 null 和 undefined)一样,不再赘述。

数值

1
2
3
4
5
6
7
8
let decLiteral: number = 6
let hexLiteral: number = 0xf00d
// ES6 中的二进制表示法
let binaryLiteral: number = 0b1010
// ES6 中的八进制表示法
let octalLiteral: number = 0o744
let notANumber: number = NaN
let infinityNumber: number = Infinity

字符串

1
let myName: string = 'Tom'

数组

写法一:「类型 + 方括号」表示法

1
let fibonacci: number[] = [1, 1, 2, 3, 5]

写法二:数组泛型

1
let fibonacci: Array<number> = [1, 1, 2, 3, 5]

元组

数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象:

1
let tom: [string, number] = ['Tom', 25]

2.6 版本后,元素个数和类型必须与声明的个数和类型一致。

枚举

枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum Days {
Sun,
Mon,
Tue,
Wed,
Thu,
Fri,
Sat,
}

console.log(Days['Sun'] === 0) // true
console.log(Days['Sat'] === 6) // true

console.log(Days[0] === 'Sun') // true
console.log(Days[6] === 'Sat') // true

也可以给枚举项手动赋值:

1
2
3
4
5
6
7
8
9
10
11
enum Days {
Sun = 7,
Mon,
Tue,
Wed,
Thu,
Fri,
Sat,
}

console.log(Days['Mon'] === 8) // true

上面的例子中,未手动赋值的枚举项会接着上一个枚举项递增。如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 不会察觉到这一点,后面的值会覆盖前面的值,手动赋值的枚举项也可以为小数或负数。

常数枚举是使用 const enum 定义的枚举类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
const enum Directions {
Up,
Down,
Left,
Right,
}

let directions = [
Directions.Up,
Directions.Down,
Directions.Left,
Directions.Right,
]

常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员,压缩了代码体积。上例的编译结果是:

1
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */]

any

任意值(Any)用来表示允许赋值为任意类型:

1
let arr: any[] = [1, 2, 3, 'a', 'b']

void

一般用 void 表示没有任何返回值的函数:

1
2
3
function alertName(): void {
alert('My name is Tom')
}

null 和 undefined

在 TypeScript 中,可以使用 null 和 undefined 来定义这两个原始数据类型:

1
2
let u: undefined = undefined
let n: null = null

与 void 的区别是,undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量:

1
2
3
4
let num1: number = undefined

let u: undefined
let num2: number = u

never

never 一般用于抛出异常或陷入死循环的情况:

1
2
3
const errorFunc = (massage: string): never => {
throw new Error(message)
}
1
2
3
const infiniteFunc = (): never => {
while (true) {}
}

object

1
let o: object = {}

类型断言

如果没有明确的指定类型,那么 TypeScript 会依照类型断言(Type Inference)的规则推断出一个类型。

1
2
3
4
5
let myFavoriteNumber = 'seven'

// 等价于

let myFavoriteNumber: string = 'seven'

如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查。

1
2
3
let myFavoriteNumber
myFavoriteNumber = 'seven'
myFavoriteNumber = 7

联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种。

1
2
3
let myFavoriteNumber: string | number
myFavoriteNumber = 'seven'
myFavoriteNumber = 7

当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:

1
2
3
4
5
function getLength(something: string | number): number {
return something.length
}

// 错误,number没有length属性

联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:

1
2
3
4
5
let myFavoriteNumber: string | number
myFavoriteNumber = 'seven'
console.log(myFavoriteNumber.length) // 5
myFavoriteNumber = 7
console.log(myFavoriteNumber.length) // 编译时报错

接口

在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

简单的例子

1
2
3
4
5
6
7
8
9
interface IPerson {
name: string
age: number
}

let tom: IPerson = {
name: 'Tom',
age: 25,
}

定义的变量比接口少了一些属性是不允许的,多一些属性也是不允许的。赋值的时候,变量的形状必须和接口的形状保持一致。

可选属性

1
2
3
4
5
6
7
8
9
10
11
12
13
interface IPerson {
name: string
age?: number
}

let tom: IPerson = {
name: 'Tom',
}

let sam: IPerson = {
name: 'Sam',
age: 22,
}

任意属性

1
2
3
4
5
6
7
8
9
10
interface IPerson {
name: string
age?: number
[propName: string]: any
}

let tom: IPerson = {
name: 'Tom',
gender: 'male',
}

只读属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface IPerson {
readonly id: number
name: string
age?: number
[propName: string]: any
}

let tom: IPerson = {
id: 89757,
name: 'Tom',
gender: 'male',
}

tom.id = 9527 // 报错,id为只读属性

注意,只读属性必须在对象赋值时进行赋值。

接口的继承

1
2
3
4
5
6
7
8
9
10
11
12
interface IVegetables {
color: string
}

interface ITomato extends IVegetables {
redius: number
}

const tomato: ITomato = {
redius: 1,
color: 'red',
}

小应用:计数器

3.1 版本后,支持了直接给函数添加属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface ICounter {
(): void
count: number
}

const getCounter = (): ICounter => {
const c = () => {
c.count++
}
c.count = 0
return c
}

const counter: ICounter = getCounter()

counter() // counter.count === 1
counter() // counter.count === 2

函数

简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
// 函数声明(Function Declaration)
function sum(x: number, y: number): number {
return x + y
}

// 函数表达式(Function Expression)
let mySum: (x: number, y: number) => number = function (
x: number,
y: number
): number {
return x + y
}

注意,输入多余的(或者少于要求的)参数,是不被允许的。
对于函数表达式,注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>。在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。等号左边的 mySum 可以通过赋值操作进行类型推论而推断出来,故可简写为:

1
2
3
let mySum = function (x: number, y: number): number {
return x + y
}

用接口定义函数的形状

采用接口定义函数时,对等号左侧进行类型限制,可以保证以后对函数名赋值时保证参数个数、参数类型、返回值类型不变:

1
2
3
4
5
6
7
8
interface SearchFunc {
(source: string, subString: string): boolean
}

let mySearch: SearchFunc
mySearch = function (source: string, subString: string) {
return source.search(subString) !== -1
}

用类型别名定义函数的形状

类型别名用来给一个类型起个新名字:

1
2
3
4
5
6
type SearchFunc = (source: string, subString: string) => boolean

let mySearch: SearchFunc
mySearch = function (source: string, subString: string) {
return source.search(subString) !== -1
}

可选参数

接口中的可选属性类似,用 ? 表示可选的参数:

1
2
3
4
5
6
7
8
9
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName
} else {
return firstName
}
}
let tomcat = buildName('Tom', 'Cat')
let tom = buildName('Tom')

需要注意的是,可选参数必须接在必需参数后面。

参数默认值

在 ES6 中,我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数:

1
2
3
4
5
function buildName(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName
}
let tomcat = buildName('Tom', 'Cat')
let tom = buildName('Tom')

此时就不受「可选参数必须接在必需参数后面」的限制了。

剩余参数

ES6 中,可以使用 …rest 的方式获取函数中的剩余参数(rest 参数),所以我们可以用数组的类型来定义 rest:

1
2
3
4
5
6
7
8
function push(array: any[], ...items: any[]) {
items.forEach(function (item) {
array.push(item)
})
}

let a = []
push(a, 1, 2, 3)

注意,rest 参数只能是最后一个参数。

重载

重载允许一个函数接受不同数量或类型的参数时,作出不同的处理 :

1
2
3
4
5
6
7
8
9
function reverse(x: number): number
function reverse(x: string): string
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''))
} else if (typeof x === 'string') {
return x.split('').reverse().join('')
}
}

上例中,重复定义了多次函数 reverse,前几次都是函数定义,最后一次是函数实现。注意,TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。

泛型

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

简单的例子

1
2
3
4
5
6
7
8
9
10
11
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}

createArray<string>(3, 'x') // ['x', 'x', 'x']

createArray(3, 1) // [1, 1, 1]

在函数名后添加了 <T>,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array<T> 中即可使用,保证了 value 与 Array 类型一致。

多个类型参数

1
2
3
4
5
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}

swap([7, 'seven']) // ['seven', 7]

泛型约束

1
2
3
4
5
6
7
8
interface Lengthwise {
length: number
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}

上例中使用了 extends 约束了泛型 T 必须符合接口 Lengthwise 的形状,也就是必须包含 length 属性。这样写可以使函数中使用 length 属性时不报错,同时也可以为 T 的类型作约束。多个类型参数之间也可以互相约束:

1
2
3
4
5
6
7
8
9
10
function copyFields<T extends U, U>(target: T, source: U): T {
for (let id in source) {
target[id] = (<T>source)[id]
}
return target
}

let x = { a: 1, b: 2, c: 3, d: 4 }

copyFields(x, { b: 10, d: 20 })

泛型接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface CreateArrayFunc {
<T>(length: number, value: T): Array<T>
}

let createArray: CreateArrayFunc
createArray = function <T>(length: number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}

createArray(3, 'x') // ['x', 'x', 'x']

也可以把泛型参数提前到接口名上,此时在使用泛型接口的时候,需要定义泛型的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface CreateArrayFunc<T> {
(length: number, value: T): Array<T>
}

let createArray: CreateArrayFunc<any>
createArray = function <T>(length: number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}

createArray(3, 'x') // ['x', 'x', 'x']

泛型参数的默认类型

2.3 以后,可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用:

1
2
3
4
5
6
7
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}

public private 和 protected

TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected:

  1. public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的。
  2. private 修饰的属性或方法是私有的,不能在声明它的类的外部访问。
  3. protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的。

需要注意的是:

  1. TypeScript 编译之后的代码中,并没有限制 private 属性在外部的可访问性。
  2. 当构造函数修饰为 private 时,该类不允许被继承或者实例化。
  3. 当构造函数修饰为 protected 时,该类只允许被继承。
  4. 修饰符和 readonly 可以使用在构造函数参数中,等同于类中定义该属性同时给该属性赋值。如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面。

抽象类

abstract 用于定义抽象类和其中的抽象方法。抽象类不允许被实例化,抽象类中的抽象方法必须被子类实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract class Animal {
public name
public constructor(name) {
this.name = name
}
public abstract sayHi()
}

class Cat extends Animal {
public sayHi() {
console.log(`Meow, My name is ${this.name}`)
}
}

let cat = new Cat('Tom')

需要注意的是,即使是抽象方法,TypeScript 的编译结果中,仍然会存在这个类。

类与接口

实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface Alarm {
alert(): void
}

class SecurityDoor extends Door implements Alarm {
alert() {
console.log('SecurityDoor alert')
}
}

class Car implements Alarm {
alert() {
console.log('Car alert')
}
}

一个类可以实现多个接口,接口可以继承接口。接口甚至也可以继承类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Point {
x: number
y: number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
}

interface Point3d extends Point {
z: number
}

let point3d: Point3d = { x: 1, y: 2, z: 3 }

因为当声明 class Point 时,除了会创建一个名为 Point 的类之外,同时也创建了一个名为 Point 的类型(TS 中最重要的类型检查功能中的类型)。

高级类型

交叉类型(Intersection Types)

交叉类型是将多个类型合并为一个类型。这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface A {
name: string
age: number
sayName: (name: string) => void
}
interface B {
name: string
gender: string
sayGender: (gender: string) => void
}

let a: A & B

// 都是合法的
a.age
a.sayName

类型断言和类型保护

有时需要强行给某个字段或方法设定类型以使用对应的属性,就要使用类型断言。有两种语法<类型>值值 as 类型

1
2
3
4
5
let someValue: any = 'this is a string'
let strLength: number = (<string>someValue).length

let someValue: any = 'this is a string'
let strLength: number = (someValue as string).length

使用类型断言,需要多次判断十分麻烦。所以使用类型保护。类型保护是param is SomeType的形式,用来明确一个联合类型变量的具体类型:

1
2
3
function isFish(pet: Fish | Bird): pet is Fish {
return (<Fish>pet).swim !== undefined
}

typeof 类型保护用于 number, string, boolean, symbol:

1
2
3
4
5
if (typeof v === 'string') {
console.log(v.length)
} else {
console.log(v.toFixed())
}

索引类型

keyof 关键字是索引类型查询操作符,能够获得任何类型上已知的公共属性名(非 never、undefined、null 类型)的联合:

1
2
3
4
5
6
7
8
9
10
11
12
interface P {
name: string
age: number
}
const people: P = {
age: 20,
name: 'wang',
}
const fn: <P, T extends keyof P>(p: P, t: T[]) => Array<P[T]> = (p, t) => {
return t.map((item) => p[item])
}
const res = fn(people, ['age'])

映射类型

TypeScript 提供了从旧类型中创建新类型的一种方式。在映射类型里新类型以相同的形式去转换旧类型里每个属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface Person {
name: string
age: number
}

type Readonly<T> = {
readonly [P in keyof T]: T[P]
}

type Partial<T> = {
[P in keyof T]?: T[P]
}

type PersonReadonly = Readonly<Person>
type PersonPartial = Partial<Person>

结果如下:

1
2
3
4
5
6
7
8
9
interface PersonPartial {
name?: string
age?: number
}

interface PersonReadonly {
readonly name: string
readonly age: number
}

字面量类型

字符串字面量类型用来约束取值只能是某几个字符串中的一个:

1
2
3
4
type EventNames = 'click' | 'scroll' | 'mousemove'
function handleEvent(ele: Element, event: EventNames) {
// do something
}

unknown

使用 any 类型,就无法享受 TypeScript 大量的保护机制。3.0 引入了新的 unknown 类型,它是 any 类型对应的安全类型。

  1. unknown 类型只能被赋值给 any 类型和 unknown 类型本身。
  2. 在交叉类型中,任何类型都可以吸收 unknown 类型。这意味着将任何类型与 unknown 相交不会改变结果类型。
  3. 在联合类型中,unknown 类型会吸收任何类型。这就意味着如果任一组成类型是 unknown,联合类型也会相当于 unknown。
  4. never 是 unknown 的子类型。
  5. 类型为 unknown 的值上使用的运算符只有相等或不等。

条件类型

2.8 版本后开始支持条件类型,增加了语言的灵活性。形如T extends U ? X : Y,若类型 T 可被赋值给类型 U,那么结果类型就是 X 类型,否则就是 Y 类型。

1
2
3
4
5
6
7
8
9
10
11
type TypeName<T> = T extends string
? 'string'
: T extends number
? 'number'
: T extends boolean
? 'boolean'
: T extends undefined
? 'undefined'
: T extends Function
? 'Function'
: 'object'

分步式条件类型:(A | B) extends U ? X : Y,等价于(A extends U ? X : Y) | (B extends U ? X : Y)

杂项

命名空间

命名空间是一种内部模块,同文件的其他地方或其他文件只能访问到该空间的导出内容。下面是同文件引用的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean
}

const lettersRegexp = /^[A-Za-z]+$/
const numberRegexp = /^[0-9]+$/

export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s)
}
}

export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s)
}
}
}

let strings = ['Hello', '98052', '101']

let validators: { [s: string]: Validation.StringValidator } = {}
validators['ZIP code'] = new Validation.ZipCodeValidator()
validators['Letters only'] = new Validation.LettersOnlyValidator()

for (let s of strings) {
for (let name in validators) {
console.log(
`"${s}" - ${
validators[name].isAcceptable(s) ? 'matches' : 'does not match'
} ${name}`
)
}
}

声明合并

相同名称的接口会合并。不同接口中如有相同属性,后出现的属性会覆盖先出现的属性。

命名空间可以和同名命名空间、同名类、同名函数、同名枚举合并。同名类和同名函数需置于命名空间前。

声明文件

假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过 script 标签引入 jQuery,然后就可以使用全局变量 $ 或 jQuery 了。但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么,这时就需要声明语句。

1
2
3
declare var jQuery: (selector: string) => any

jQuery('#foo')

上例中,declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。其他类型的声明有:
declare var 声明全局变量
declare function 声明全局方法
declare class 声明全局类
declare enum 声明全局枚举类型
declare namespace 声明(含有子属性的)全局对象
interfacetype 声明全局类型
export 导出变量
export namespace 导出(含有子属性的)对象
export default ES6 默认导出
export = commonjs 导出模块
export as namespace UMD 库声明全局变量
declare global 扩展全局变量
declare module 扩展模块
/// <reference /> 三斜线指令

通常会把声明语句放到一个单独的文件(.d.ts 为后缀)中。一般来说,ts 会解析项目中所有的 _.ts 文件,当然也包含以 .d.ts 结尾的文件。所以当 .d.ts 放到项目中时,其他所有 _.ts 文件就都可以获得类型定义。

tsconfig.json 配置

在 TS 的项目中,TS 最终都会被编译 JS 文件执行,TS 编译器在编译 TS 文件的时候都会根据项目根目录 tsconfig.json 文件的配置进行编译:

files 表示编译需要编译的单个文件列表

1
2
3
4
"files": [
// 指定编译文件是src目录下的a.ts文件
"scr/a.ts"
]

include 表示编译需要编译的文件或目录

1
2
3
4
5
"include": [
// "scr" // 会编译src目录下的所有文件,包括子目录
// "scr/*" // 只会编译scr一级目录下的文件
"scr/*/*" // 只会编译scr二级目录下的文件
]

exclude 表示编译器需要排除的文件或文件夹

1
2
3
4
"exclude": [
// 排除src目录下的lib文件夹下的文件不会编译
"src/lib"
]

extends 引入其他配置文件,继承配置

1
2
// 把基础配置抽离成tsconfig.base.json文件,然后引入
"extends": "./tsconfig.base.json"

compileOnSave 设置保存文件的时候自动编译(vscode 暂不支持)

1
"compileOnSave": true

references 指定工程引用依赖

compilerOptions 配置编译选项

编译配置选项compilerOptions包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"compilerOptions": {
"incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
"tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
"diagnostics": true, // 打印诊断信息
"target": "ES5", // 目标语言的版本
"module": "CommonJS", // 生成代码的模板标准
"outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
"lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
"allowJS": true, // 允许编译器编译JS,JSX文件
"checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
"outDir": "./dist", // 指定输出目录
"rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
"declaration": true, // 生成声明文件,开启后会自动生成声明文件
"declarationDir": "./file", // 指定生成声明文件存放目录
"emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
"sourceMap": true, // 生成目标文件的sourceMap文件
"inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
"declarationMap": true, // 为声明文件生成sourceMap
"typeRoots": [], // 声明文件目录,默认时node_modules/@types
"types": [], // 加载的声明文件包
"removeComments":true, // 删除注释
"noEmit": true, // 不输出文件,即编译后不会生成任何js文件
"noEmitOnError": true, // 发送错误时不输出任何文件
"noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
"importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
"downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
"strict": true, // 开启所有严格的类型检查
"alwaysStrict": true, // 在代码中注入'use strict'
"noImplicitAny": true, // 不允许隐式的any类型
"strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
"strictFunctionTypes": true, // 不允许函数参数双向协变
"strictPropertyInitialization": true, // 类的实例属性必须初始化
"strictBindCallApply": true, // 严格的bind/call/apply检查
"noImplicitThis": true, // 不允许this有隐式的any类型
"noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
"noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
"noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
"noImplicitReturns": true, //每个分支都会有返回值
"esModuleInterop": true, // 允许export=导出,由import from 导入
"allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
"moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
"paths": { // 路径映射,相对于baseUrl
// 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
"jquery": ["node_modules/jquery/dist/jquery.min.js"]
},
"rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
"listEmittedFiles": true, // 打印输出文件
"listFiles": true// 打印编译的文件(包括引用的声明文件)
}