交叉类型 &: 多个类型合并为一个类型
- 示例:let c = 接口A & 接口B 的合并类型,c继承A和B的方法又可以使用自身方法
联合类型 |: 规定了几个类型,不同的类型使用不同的方法(和类型保护typeof一起使用)
1 2 3 4 5 6 7
| const img = (width: string | number, height: string | number) => { if(typeof.width === number){} if(typeof.width === string){} }
函数的联合类型: function foo(): a | b {}
|
类型保护与区分类型
用户自定义的类型保护
1 2 3 4 5
| interface Fish { a() } interface Flog { c() } function isFish(pet: Fish | Flog): pet is Fish { return (<Fish>pet).a !== undefined }
|
typeof类型保护
- 跟联合类型一起使用, 通过判断这个是不是要判断的类型来进入不同代码段
instanceof 类型保护: 通过构造函数来细化类型
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
| interface fu { getPaddingString(): string }
class one implements fu { constructor(private numSpaces: number) { } getPaddingString() {...} }
class two implements fu { constructor(private value: string) { } getPaddingString() {...} }
function getRandomPadder() { return Math.random() < 0.5 ? new SpaceRepeatingPadder(4) : new StringPadder(" "); } let padder: fu = getRandomPadder();
if (padder instanceof one) { padder; }
|
可以为null的类型
- ts中把null和undefined区分为两种类型,并且null和undefined可以赋值给任意类型
- 可选参数和可选属性会自动加上undefined
类型保护和类型断言: 类型保护用来去除null
1 2 3 4 5
| function f(sn: string | null): string { return sn || "default" }
|
类型别名(别名: 参数名),不会新建一个类型,只是引用
- type Tpost = a & b,Tpost是存储了a和b的方法,下次调用直接使用Tpost节省代码量
接口vs类型别名
- 类型别名不能被extends和implements
字符串字面量类型
- type A = “B” | “C” | “D” // A的值只能为B或C或D
数字字面量类型
- 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
| 1. 可辨识的特征或标签: 要联合的接口存在相同的属性 interface a { kind : "a", width : number } interface b { kind : "b", height : number } 2. 联合 type union = a | b 3. 使用: 当没有涵盖所有可辨识联合的变化,想让编译器通知使用完整性检查 function assertNever(x: 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) } }
完整性检查: 当代码变化时,让编译器提醒
|
索引类型: 通过索引去访问某个值
- 索引类型查询操作符: keyof T —> keyof T的值为T上已知的联合属性
- 如:
1 2 3 4 5 6 7
| interface Person { name: string age: number } let personProps: keyof Person; 使用: personProps = 'name'
|
- 索引访问操作符: T[K]
1 2
| const getProperty = <T, K extends keyof T>(o: T, name: K): T[K] => o[name]
|
索引类型和字符串索引签名: keyof和 T[K]与字符串索引签名进行交互。
- 如果带有一个字符串索引签名的类型,则 keyof T是 string类型,且T[string]为索引签名的类型
1 2 3 4 5
| interface Map<T> { [key: string]: T } let keys: keyof Map<number> let value: Map<number>['foo']
|
映射类型: 新类型以相同的形式去转换旧类型里每个属性
- 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>类型
- 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| type 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 }
type Pick<T, K extends keyof T> = { [P in K]: T[P]; } type Record<K extends string, T> = { [P in K]: T; }
|
- 常用:
- 1.初始化对象
1 2 3 4 5 6 7 8 9
| interface 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 9
| enum 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 8
| type Direction = "up" | "right" | "down" | "left" type RecordDirect = Record<Direction, number> const direction: RecordDirect = { up: 1, right: 2, down: 3, left: 4 }
|
条件类型
- type ConditionalType<T, U> = T extends U ? X : Y // 如果T可以赋值给U,则条件为真,类型X将被选择;否则,类型Y将被选择。
- Pick<T, K extends keyof T>:从T中选取几个属性K使用
- Extract<T, U>: 提取T中可以赋值给U的类型