zoukankan      html  css  js  c++  java
  • 白话typescript中的【extends】和【infer】(含vue3的UnwrapRef)

    大家好,我是小雨小雨,致力于分享有趣的、实用的技术文章。

    内容分为翻译和原创,如果有问题,欢迎随时评论或私信,希望和大家一起进步。

    分享不易,希望能够得到大家的支持和关注。

    extends

    typescript 2.8引入了条件类型关键字: extends,长这个样子:

    T extends U ? X : Y
    

    看起来是不是有点像三元运算符: condition ? result(1) : result(2),用大白话可以表示为:

    如果T包含的类型 是 U包含的类型的 '子集',那么取结果X,否则取结果Y

    再举几个ts预定义条件类型的例子,加深理解:

    type NonNullable<T> = T extends null | undefined ? never : T;
    
    // 如果泛型参数 T 为 null 或 undefined,那么取 never,否则直接返回T。
    let demo1: NonNullable<number>; // => number
    let demo2: NonNullable<string>; // => string
    let demo3: NonNullable<undefined | null>; // => never
    

    分配式extends

    T extends U ? X : Y
    

    其实就是当上面的T为联合类型的时候,会进行拆分,有点类似数学中的分解因式:

    (a + b) * c => ac + bc

    再举个官网的例子:

    type Diff<T, U> = T extends U ? never : T; // 找出T的差集
    type Filter<T, U> = T extends U ? T : never; // 找出交集
    
    type T30 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // => "b" | "d"
    // <"a" | "b" | "c" | "d", "a" | "c" | "f">
    // 相当于
    // <'a', "a" | "c" | "f"> |
    // <'b', "a" | "c" | "f"> |
    // <'c', "a" | "c" | "f"> |
    // <'d', "a" | "c" | "f">
    type T31 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">;  // => "a" | "c"
    // <"a" | "b" | "c" | "d", "a" | "c" | "f"> 同上
    
    let demo1: Diff<number, string>; // => number
    

    我们再来看看infer。

    infer

    在extends语句中,还支持infer关键字,可以推断一个类型变量,高效的对类型进行模式匹配。但是,这个类型变量只能在true的分支中使用。

    // 内置 ReturnType
    type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
    

    不知道初学ts的朋友们看完这个介绍是不是一脸懵逼,反正之前我是...

    其实理解之后很简单,这里直接说下我的理解,应该还算简单易懂:

    infer X 就相当于声明了一个变量,这个变量随后可以使用,是不是有点像for循环里面的声明语句?

    for (let i = 0, len = arr.length; i < len; i++) {
        // do something
    }
    

    不同的是,infer X的这个位置本应该有一个写死的类型变量,只不过用infer R替换了,更灵活。

    需要注意的是infer声明的这个变量只能在true分支中使用

    还是举几个例子,加深理解,纸上谈兵终觉浅嘛:

    例子一

    // 解读: 如果泛型变量T是 () => infer R的`子集`,那么返回 通过infer获取到的函数返回值,否则返回boolean类型
    type Func<T> = T extends () => infer R ? R : boolean;
    
    let func1: Func<number>; // => boolean
    let func2: Func<''>; // => boolean
    let func3: Func<() => Promise<number>>; // => Promise<number>
    

    例子二

    // 同上,但当a、b为不同类型的时候,返回不同类型的联合类型
    type Obj<T> = T extends {a: infer VType, b: infer VType} ? VType : number;
    
    let obj1: Obj<string>; // => number
    let obj2: Obj<true>; // => number
    let obj3: Obj<{a: number, b: number}>; // => number
    let obj4: Obj<{a: number, b: () => void}>; // => number | () => void
    

    例子三(Vue3中的UnwrapRef)

    // 如果泛型变量T是ComputedRef的'子集',那么使用UnwrapRefSimple处理infer指代的ComputedRef泛型参数V
    // 否则进一步判断是否为Ref的'子集',进一步UnwrapRefSimple
    export type UnwrapRef<T> = T extends ComputedRef<infer V>
      ? UnwrapRefSimple<V>
      : T extends Ref<infer V> ? UnwrapRefSimple<V> : UnwrapRefSimple<T>
        
    // 我是分割线
        
    // 如果T为Function | CollectionTypes | BaseTypes | Ref之一的'子集',直接返回。
    // 否则判断是否为数组的'子集',不是的话视为object,调用UnwrappedObject
    type UnwrapRefSimple<T> = T extends Function | CollectionTypes | BaseTypes | Ref
      ? T
      : T extends Array<any> ? T : T extends object ? UnwrappedObject<T> : T
    
    // 我是分割线
    // 调用UnwrapRef,产生递归效果,解决了ts类型递归
    type UnwrappedObject<T> = { [P in keyof T]: UnwrapRef<T[P]> } & SymbolExtract<T>
    
    // 我是分割线
        
    // 泛型Ref
    export interface Ref<T = any> {
      [Symbol()]: true
      value: T
    }
    
    // 我是分割线
    
    export interface ComputedRef<T = any> extends WritableComputedRef<T> {
      readonly value: T
    }
    
    // 我是分割线
    
    export interface WritableComputedRef<T> extends Ref<T> {
      readonly effect: ReactiveEffect<T>
    }
    

    建议自己捋一遍。

    总结

    ts提供的extends和infer大大增加了类型判断的灵活性和复用性,虽然用与不用都可以,但能熟练地使用高级特性将大大提升ts推断的效率和代码类型的可读性。

    如有问题,欢迎指出。

    劳动节快乐!

  • 相关阅读:
    NYOJ 10 skiing DFS+DP
    51nod 1270 数组的最大代价
    HDU 4635 Strongly connected
    HDU 4612 Warm up
    POJ 3177 Redundant Paths
    HDU 1629 迷宫城堡
    uva 796
    uva 315
    POJ 3180 The Cow Prom
    POJ 1236 Network of Schools
  • 原文地址:https://www.cnblogs.com/xiaoyuxy/p/12823032.html
Copyright © 2011-2022 走看看