ts-18 进阶用法

23 阅读3分钟

Proxy & Reflect

  • 概念
    • Proxy
      • es6新增的一个对象拦截器,类似es5的defineProperty。
      • 可以监听到一个对象的变化,取值和设置值,vue3也是通过proxy做的属性的劫持
    • Reflect
      • 配合Proxy用来操作对象
  • 例子
    •   type Person1 = {
          name: string
          age: number
          sex: string
        }
        const proxy = (obj: any, key: any) => {
          return new Proxy(obj, {
            get(target, prop, receiver) {
              console.log('get', prop)
              return Reflect.get(target, prop, receiver)
            },
            set(target, prop, value, receiver) {
              console.log('set', prop)
              return Reflect.set(target, prop, value, receiver)
            },
          })
        }
      
        // 固定的太死了
        const log1 = (obj: Person1, key: 'name' | 'age' | 'sex') => {
          return proxy(obj, key)
        }
      
        let ps1: Person1 = log1(
          {
            name: '亚索',
            age: 18,
            sex: '男',
          },
          'name'
        )
      
        ps1.name = '瑞雯'
        ps1.sex
        console.log(ps1)
      
        // 优化后
        const log2 = <T>(obj: T, key: keyof T): T => {
          return proxy(obj, key)
        }
      
        let ps2 = log2(
          {
            name: '盲僧',
            age: 20,
            sex: '男',
            like: 'hs',
          },
          'like'
        )
      
        ps2.like
      

Partial & Pick

  • 内置高级类型Partial Pick
  • Partial
    •   type Person1 = {
          name: string;
          age: number;
          msg: string;
        };
      
        type p = Partial<Person1>;
      
    • 源码
      • type Partial<T> = {
          [P in keyof T]?: T[P]
        }
        
      • keyof 什么意思
        • keyof 之后所有的key 都会变成这样 类似 for in
        • type key = 'name' | 'age' | 'msg';
  • Pick
    • 选取指定一组属性,返回一个新的类型定义
    •   type Person1 = {
          name: string;
          age: number;
          msg: string;
        };
      
        type p = Pick<Person, 'name'>
      
    • 源码
      •   type Pick<T, K extends keyof T> = {
            [P in K]: T[P]
          }
        
      • K extends keyof T 什么意思呢
        • K 我们这传了个联合类型 通过 extends约束了下 你只能传你的约束的那些值 type key = 'name' | 'age' | 'msg'
        •   type p = Pick<Person, 'xxxx'> // error 
          

Record & Readonly

  • Readonly
    • 类似 Partial
    • 例子
      •   type Person1 = {
            name: string
            age: number
            msg: string
          }
        
          type p1 = Readonly<Person1>
          // p1 会变成这样
          // type p1 = {
          //     readonly name: string;
          //     readonly age: number;
          //     readonly msg: string;
          // }
        
    • 源码
      • 也是通过 keyof 把key变成联合类型 type key = 'name' | 'age' | 'msg';
      • 然后通过in 遍历 给每个key 前面添加 readonly
  • Record
    • 例子
      • 用来约束key,有两个参数
      •   type Person1 = {
            name: string
            age: number
            msg: string
          }
        
          type K = 'A' | 'B' | 'C'
        
          type p1 = Record<K, Person1>
        
          // 使用
          let obj3: p1 = {
            A: { name: '亚索', age: 18, msg: '嘻嘻' },
            B: { name: '亚索', age: 18, msg: '嘻嘻' },
            C: { name: '亚索', age: 18, msg: '嘻嘻' },
          }
        
    • 源码
      •   type Record<K extends keyof any, T> = {
            [P in K]: T
          }
        
      •   // keyof any 什么意思?
          type key = string | number | symbol
        

infer

  • 基础用法
    • 新增的关键字充当占位符
    • 例子
      • 需求:定义一个类型 如果是数组类型 就返回 数组元素的类型 否则 就传入什么类型 就返回什么类型
      • 以前可能会这么写
        •  type Type<T> = T extends Array<any> ? T[number] : T
          
           type T1 = Type<(number | string)[]>
          
           type T2 = Type<boolean>
          
      • 使用infer
        •  type Type<T> = T extends Array<infer U> ? U : T
          
           type T1 = Type<(number | string)[]>
          
           type T2 = Type<boolean>
          
      • 也可以约束成 never
        •  // 只能传联合类型 不满足 就返回 never
           type Type<T> = T extends Array<infer U> ? U : never
          
           type T1 = [string, number] // [string, number]
          
           type T2 = Type<boolean> // never
          
          
  • 类型提取
    • 提取头部元素
      •   type First<T extends any[]> = T extends [infer one, ...any[]] ? one : []
        
          type T1 = First<Arrs> // type a = "a"
        
    • 提取尾部元素
      •   type Last<T extends any[]> = T extends [...any[], infer Last] ? Last : []
        
          type T2 = Last<Arrs> // type b = "c"
        
    • 删除头部元素
      •   type Shift<T extends any[]> = T extends [unknown, ...infer Rest] ? Rest : []
        
          type T3 = Shift<Arrs> // type T3 = type T3 = ["b", "c"]
        
    • 删除尾部元素
      •   type Pop<T extends any[]> = T extends [...infer Rest, unknown] ? Rest : []
        
          type T4 = Pop<Arrs> // type T4 = ["a", "b"]
        
        
  • 递归
    • 需求
      •   // 需求 Arr1 正常排序 变成 Arr2 那样
          type Arr1 = [6, 5, 4, 3, 2, 1]
          type Arr2 = [1, 2, 3, 4, 5, 6]
        
    • 思路
      • 使用泛型约束 只能传数组类型
      • 然后提取第一个放入末尾, 循环操作 形成递归 满足条件 返回
    • 例子
      •   type ReveArr<T extends any[]> = T extends [infer First, ...infer rest]
            ? [...ReveArr<rest>, First]
            : T
        
          type Result = ReveArr<Arr1> // type Result = [1, 2, 3, 4, 5, 6]