交叉类型 &: 多个类型合并为一个类型
- 『let c = 接口A & 接口B』 的合并类型,c继承A和B的方法又可以使用自身方法
联合类型 |: 规定了几个类型,不同的类型使用不同的方法(和类型保护typeof一起使用)
1 | const img = (width: string | number, height: string | number) => { |
类型保护与区分类型
用户自定义的类型保护
1 | interface Fish { a() } |
typeof类型保护
- 跟联合类型一起使用, 通过判断这个是不是要判断的类型来进入不同代码段
instanceof 类型保护: 通过构造函数来细化类型
1 | interface fu { // 父类 |
可以为null的类型
- ts中把『null和undefined区分为两种类型』,并且null和undefined可以赋值给任意类型
- 可选参数和可选属性会自动加上undefined
类型保护和类型断言: 『类型保护用来去除null』
1 | function f(sn: string | null): string { |
类型别名(别名: 参数名)
- 不会新建一个类型,只是引用
1
2type Tpost = a & b // Tpost存储了a和b的方法
// 当遇见a,b的复合类型时直接调用Tpost即可
接口vs类型别名
- 类型别名不能被extends和implements
字符串字面量类型
1 | type A = "B" | "C" | "D" // A的值只能为"B"或"C"或"D" |
数字字面量类型
1 | type A = 0 | 1 | 2 // A的值只能为0或1或2 |
可辨识联合
- 合并单例类型,联合类型,类型保护和类型别名来创建一个叫做『可辨识联合的高级模式』,也叫做『标签联合』或『代数数据类型』
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
261. 可辨识的特征或标签: 要联合的接口存在相同的属性
interface a {
kind : "a",
width : number
}
interface b {
kind : "b",
height : number
}
2. 联合
type union = a | b
3. 使用: 当没有涵盖所有可辨识联合的变化,想让编译器通知使用完整性检查
function assertNever(x: never): never { // 使用never类型,来检查
throw new Error("Unexpected object: " + x)
}
function f(r: union): string { // 完整性检查的方法一: 指定类型
switch (r.kind) {
case "a": return r.width
case "b": return r.height
default: return assertNever(r) // 存在除这两种情况的返回assertNever函数
}
}
完整性检查: 当代码变化时,让编译器提醒
索引类型: 通过索引去访问某个值
- 索引类型查询操作符: 『keyof T』,其值为T上已知的联合属性
1
2
3
4
5
6
7interface Person {
name: string
age: number
}
let personProps: keyof Person; // 'name' | 'age'
使用:
personProps = 'name' // 指的是key值 - 索引访问操作符: 『T[K]』
1
2const getProperty = <T, K extends keyof T>(o: T, name: K): T[K] => o[name]
// o[name]:选择T中的K(name这个key)得到对应key的value
索引类型和字符串索引签名: keyof和 T[K]与字符串索引签名进行交互
- 如果带有一个字符串索引签名的类型,则 keyof T是 string类型,且T[string]为索引签名的类型
1
2
3
4
5interface Map<T> {
[key: string]: T
}
let keys: keyof Map<number> // T的类型为number,遍历key,得到的类型为string
let value: Map<number>['foo'] // T的类型为number,获取当key等于foo的值,值为number类型
映射类型: 新类型以相同的形式去转换旧类型里每个属性
- Readonly
: T中的属性都为只读 - Partial
:T中的属性都为可选 - Record<K extends string, T>:从T中获取key,T为value的类型
- Pick<T, K extends keyof T>:从T中选取几个属性K使用 条件类型
- Exclude<T, U>: 从T中剔除可以赋值给U的类型
- Extract<T, U>: 提取T中可以赋值给U的类型 条件类型
- NonNullable
: 从T中剔除null和undefined - ReturnType
: 获取函数返回值类型。 - InstanceType
: 获取构造函数类型的实例类型。 - Pick<T, Exclude<keyof T, K>>: 实现Omit<T, K>类型
- ConditionalType<T, U>: 如果T可以赋值给U,则条件为真,类型X将被选择;否则,类型Y将被选择。条件类型
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19type Readonly<T> = { // 只读
readonly [P in keyof T]: T[P]
}
type Partial<T> = { // 可选
[P in keyof T]?: T[P]
}
type PersonPartial = Partial<Person> // 使用
type ReadonlyPerson = Readonly<Person>
type Flags = { [K in Keys]: boolean } // k遍历keys,将值添加在flags中,值的类型为boolean
type Pick<T, K extends keyof T> = { // 类型
[P in K]: T[P];
}
type Record<K extends string, T> = { // 不需要类型
[P in K]: T;
}
type ConditionalType<T, U> =
T extends U ? X : Y // 条件类型, 如果T可以赋值给U,则条件为真,类型X将被选择;否则,类型Y将被选择。
常用的映射类型:
- 1.初始化对象
1
2
3
4
5
6
7
8
9interface IPerson {
name: string
age: number
}
type Person = Record<keyof IPerson, string>
const person: Person = {
name: "moli",
age: "26"
} - 2.枚举值管理
1
2
3
4
5
6
7
8
9enum Color {
Red="RED"
Green="GREEN"
}
type ColorHex = Recode<Color, string>
const colorHex: ColorHex = {
[Color.Red]: "#FF0000",
[Color.Green]: "#00FF00"
} - 3.字面量
1
2
3
4
5
6
7
8type Direction = "up" | "right" | "down" | "left"
type RecordDirect = Record<Direction, number>
const direction: RecordDirect = {
up: 1,
right: 2,
down: 3,
left: 4
}