交叉类型

  • & ```typescript const mergeFunc = (arg1: T, arg2: U): T & U => { const res = {} as T & U res = Object.assign(arg1, arg2) return res }

// 利用 mergeFun 我们可以合并两个对象为一个对象 mergeFunc({a: ‘a’}, {b: ‘b’}) // 结果为 {a: ‘a’, b: ‘b’}

  1. <a name="Isjki"></a>
  2. ### 联合类型
  3. - 类型是多种类型中的任意一个,符号 |
  4. ```typescript
  5. const data: string | number // data 既可以是 string 又可以是 number

类型保护

  • 当一个函数可能返回多种情况值类型,这时候我们需要类型保护,不然ts不知道该函数的返回值类型是什么

    typeof

  • 使用 typeof 类型保护 (string/number/boolean/symbol) 中的一种 ```typescript const func: () => string | number const data = func() //此时data 可能是string 也可能是 number

//使用 typeof 类型保护 (string/number/boolean/symbol) 中的一种

if(typeof data === ‘string’) { // data.length } else { // data.toFixed() }

  1. - typeof 用在TypeScript 中,含义跟JavaScript中不同。不再简单的表示 跟在它后面的值的类型
  2. - let instance : ClassA; 表示的是 instance 的类型是ClassA的实例
  3. - let classA: typeof ClassA; 表示的是 classA 的类型就是 ClassA
  4. <a name="NS0AR"></a>
  5. #### instranceof
  6. - 判断实例是由哪个类创建的
  7. ```typescript
  8. class A {
  9. public age: number
  10. constructor() {}
  11. }
  12. class B {
  13. public name: string
  14. constructor() {}
  15. }
  16. const data : A | B // 简单表示 data 是 A B 类当中的某一个实例
  17. if(data instranceof A) {
  18. //...
  19. } else {
  20. //...
  21. }

类型别名 type

  • 引用其他类型使用(为其他类型起个新的名字使用)
  • 抽象代码使用 ```typescript type TypeString = string const str: TypeString

//在泛型中使用 type PositionType = { x: T, y: T } const p1: PositionType = { x: 1, y: 1 }

const p2: PositionType = { x: ‘left’, y: ‘left’ }

//树形 type Childs = { current: T, child?: Childs }

const data: Childs = { current: ‘str’, child: { current: ‘str’, child: { current: ‘str’, } } }

// 固定值类型 type Direction = ‘north’ | ‘east’ | ‘south’ | ‘west’

const func = (direction: Direction) => { //direction的值只能是 ‘north’ | ‘east’ | ‘south’ | ‘west’ 中的一个 }

type Count = 10

interface App { name: string, pod: Count }

  1. <a name="hHbyF"></a>
  2. ### 可辨识联合
  3. - 具有普通的单例类型属性
  4. - 一个类型中包括了多种类型的联合
  5. ```typescript
  6. //①首先我们先mock几个具有普通的单例类型属性的接口
  7. interface Square {
  8. kind: 'square';
  9. size: number
  10. }
  11. interface Rectangle {
  12. kind: 'rectangle';
  13. height: number;
  14. weight: number;
  15. }
  16. interface Circle {
  17. kind: 'circle';
  18. radius: number;
  19. }
  20. //②使用类型别名 type 声明一个联合类型,包括以上3中类型
  21. type Shape = Square | Rectangle | Circle
  22. const assertNever = (v: never): never => { // never 的一般使用
  23. throw new Error(`Unexpected .....${v}`)
  24. }
  25. const getArea = (shape: Shape) => {
  26. switch(shape.kind) {
  27. case 'square':
  28. return shape.size * shape.size
  29. case 'rectangle':
  30. return shape.height * shape.height
  31. case 'circle':
  32. return Math.PI * shape.radius ** 2 // ES7语法 ** 2 表示 平法
  33. default: return assertNever(shape)
  34. }
  35. }

this类型使用

链式调用

  • 在class 类中的 this 代表该类的实例对象 ```typescript class Counter { constructor(public count: number) { } public add(v: number) { this.count += v return this }

    public subtract(v: number) { this.count -= v return this } }

const counter: Counter = new Counter(10) // 链式调用 counter.add(1).subtract(4)

  1. 在子类中也能实现链式调用
  2. ```typescript
  3. class PowCounter extends Counter {
  4. constructor(public count: number =0 ) {
  5. super(count)
  6. }
  7. public pow(v: number){
  8. this.count = this.count ** v
  9. return this
  10. }
  11. }
  12. const powCounter: PowCounter = new PowCounter(2)
  13. // 链式调用
  14. powCounter.pow(2).add(4).subtract(1)

索引属性

keyof

  • 连接一个类型,返回该类型所有属性的联合类型

    1. interface A {
    2. name: string;
    3. age: number
    4. }
    5. //此时data 的值只能是 name 或者 age
    6. const data: keyof A === const data: string | number
  • 泛型中使用,获取一个对象属性的值

    1. const getValue = <T, K extends keyof T>(obj: T, names: K[]): Array<T[K]> => {
    2. return names.map(n => obj[n])
    3. }
    4. // Array<T[K]> === T[K][]
    5. const mockObj = {
    6. name: 'zxc',
    7. age: 18
    8. }
    9. const value: (string | number)[] = getValue(mockObj, ['name', 'age'])

    索引访问操作符

  • 比如: 把一个类型转换成每个字段都是只读的或者可选的 ```typescript interface App { name: string; status: number; desc: string; }

// 需要把App 接口(或者 更多接口)的属性修改为只读或者可选 type ReadonlyType = { // 相当于一个函数 readonly P in keyof T?: T[P] // in === for in }

type ReadonlyApp = ReadonlyType

//这样我们定义的对象用ReadonlyApp 类型,它的属性就是只读以及可选 const app: ReadonlyApp = { name: ‘app’, status: 1, desc: ‘app desc’; }

  1. - 其实 ts 中已经封装了 类似于上面思想的 type 类,即 pick
  2. ```typescript
  3. // ts 封装的 Pick 类
  4. type Pick<T, K extends keyof T> = {
  5. [P in K]: T[P]
  6. }
  7. // 使用一下 pick
  8. const pick = <T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> => {
  9. const res: any = {}
  10. keys.map(key => {
  11. res[key] = obj[key]
  12. })
  13. return res
  14. }
  15. // 我们测试一下
  16. const mockData = {
  17. name: 'zxc',
  18. age: 18,
  19. addr: 'hangzhou'
  20. }
  21. console.log(pick(mockData, ['name', 'age']))// { name: 'zxc', age: 18 }
  22. console.log(pick(mockData, ['name', 'addr']))// { name: 'zxc', addr: 'hangzhou'}
  • Record— 把一个对象属性的值转换成其他类型 ```typescript // ts 封装的 Record 类 type Record = {

}

//我们看一下 Record 类的用法 const mapObject = (obj: Record, fn: (x: T) => U ): Record => { const res: any = {} for(const key in obj){ res[key] = f(obj[key]) } return res }

const mockData = { a: ‘hello’, b: ‘world’, c: ‘str’ }

const newObj = mapObject(mockData, (s) => s.length) console.log(newObj) // { a: 5, b: 5, c: 3 }

  1. **我们使用映射类型 对一个对象进行加工操作后,我们也可以进行拆包操作(我觉得叫还原更贴切,即 封装/还原)**
  2. ```typescript
  3. type Proxy<T> = {
  4. get(): T;
  5. set(value: T): void; // 之前说过 存取器中 set函数没有返回值
  6. }
  7. type Proxify<T> = {
  8. [P in keyof T]: Proxy<T[P]> // 把遍历的每一个值都放进去
  9. }
  10. const proxify = <T>(obj: T): Proxify<T> => {
  11. const res = {} as Proxify<T>
  12. for(const key in obj){
  13. res[key] = {
  14. get:() => obj[key],
  15. set:(value) => obj[key = value
  16. }
  17. }
  18. return res
  19. }
  20. // 我们测试一下
  21. const mockData = {
  22. name: 'zxc',
  23. age: 18
  24. }
  25. const newobj = proxify(mockData)

打印结果:对象的每个属性都具备了 get 和 set 方法
image.png
我们再将对象拆包(还原)

  1. const unProxify = <T>(data: Proxify<T>): T => {
  2. const res = {} as T
  3. for(const k in data){
  4. res[key] = data[key].get()
  5. }
  6. return res
  7. }
  8. let originalObj = unProxify(newobj)
  9. console.log(originalObj) // 得到原始对象 {name : 'zxc', age: 18 }

元组和数组上的映射类型

看一下promise 的使用

  1. type MapToPromise<T> = {
  2. [K in typeof T]: Promise<T[K]> //定义返回的值都是Promise
  3. }
  4. type Tuple = [number, string, boolean]
  5. type PromiseTuple: MapToPromise<Tuple>
  6. const data: PromiseTuple = [
  7. new Promise((resolve, reject) => resolve(1)),
  8. new Promise((resolve, reject) => resolve('a')),
  9. new Promise((resolve, reject) => resolve(false)),
  10. ]
  11. // 注意 data 的类型即
  12. const data: [Promise<number>, Promise<string>, Promise<boolean>]

unknown类型

  1. 任何类型都可以复制给unknown类型

    1. const value: unknown
    2. value = 1
    3. value = 'a'
  2. 如果没有类型断言或者基于控制流的类型细化,unknown不可以赋值给其他类型,只能赋值给any或者它本

    1. const value: unknown
    2. const value1: string
    3. value1 = value // 是错误的
  3. 如果没有类型断言或者基于控制流的类型细化,不能在它身上进行任何操作

    1. const value: unknown
    2. value++ // 是错误的
  4. unknown与其他类型组成的交叉类型,最后都等于其他类型

    1. type A = string & unknown
    2. const data: A // data 的类型为string
  5. unknown与其他类型除了(any)组成的联合类型,都等于unknown类型

    1. type A = string | unknown // A 为 unknown
    2. type B = any | unknown // B 为 any (any 特殊)
  6. never 类型是 unknown 的子类型

  7. keyof unknown 等于类型 never

    1. type A = keyof unknown // A 类型为 never
  8. 只能对 unknown 进行等或者不等操作,不能进行其他的操作

    1. const value: unknown = 1
    2. const value1: unknown = 2
    3. value !== value1
  9. 使用映射类型时,如果遍历的是unknown类型,则不会映射任何属性 ```typescript type A = {

}

type B = A // 映射出来的 { [x: string]: number } type C = A // 映射出来的 {} 空对象

  1. <a name="kEjhj"></a>
  2. ### 条件类型
  3. - T extends U ? X : Y
  4. ```typescript
  5. type A<T> = T extends string ? string : number
  6. const data: A<10> // data就是一个number 类型的值
  7. // 灵活使用
  8. type A<T> =
  9. T extends string ? string :
  10. T extends number ? number :
  11. T extends boolean ? boolean :
  12. T extends undefined ? undefined :
  13. T extends () => void ? () => void :
  14. object
  15. type B = A<() => void> // 此时B类型就是一个函数类型
  16. type C = A<string[]> // 此时C类型就是一个 object 类型
  17. type D = A<(() => void) | string[]> // 此时D类型就是一个 函数类型 和 object 类型组成的联合类型
  18. // 实际应用
  19. type Diff<T, U> = T extends U ? never : T
  20. type A = Diff<string | number | booleanundefined | number> // A类型就是 string | boolean

注意:ts 2.8版本以上已封装了类似 Diff 类型的用法—-Exclude

  1. type A = Exclude<'a' | 'b' | 'c', 'a' | 'b'> // A 类型就是 c 类型
  2. // 从前半部分挑出 后半部分没有的类型

类型推断

infer(条件类型的类型推断)

  1. //不使用 infer
  2. type A<T> = T extends any[] ? T[number] : T // 是数组的话返回数组中元素的类型否则返回它本身类型
  3. type B = A<string[]> // B 就是 string 类型,因为数组的元素是 string 类型
  4. type B = A<string> // B 也是 string 类型
  5. 使用 infer
  6. type A<T> = T extends Array<infer U> ? U : T
  7. type B = A<string[]> // B 就是 string 类型,因为数组的元素是 string 类型
  8. type B = A<string> // B 也是 string 类型

Extract

  • 从T 中找出可以 赋值 给U 的(联合)类型

    1. type A = Extract<'a' | 'b' | 'c', 'c'> // A 就是c 类型

    NonNullable

  • 从 T 中除去 null 和 undefined 类型

    1. // A === string | number
    2. type A = NonNullable<string | number | null | undefined >

    ReturnType

  • 返回一个函数返回值的类型

    1. type A = ReturnType<() => string> // A === string

    InstanceType

  • 返回一个构造函数实例的类型

  • 只能判断类型为构造函数 以及 any ```typescript class AClass { contructor() {} }

type B = InstanceType //相当于 B === AClass ```