【问题标题】:Convert nested array type转换嵌套数组类型
【发布时间】:2022-03-18 14:29:53
【问题描述】:

我正在寻找一种可用于将任意深度的嵌套数组类型转换为另一种类型的类型。所以某种类型,ConvertToBool<T> 这样:

ConvertToBool<number[][][]> // should be boolean[][][]

我设法让它适用于非嵌套数组类型和对象类型。我什至写了this answer 用于转换对象类型的字段,除了嵌套数组的情况外,它工作得很好。

现在我想写一个这样的类型:

type Primitive = string | number | boolean | null | undefined;

type ConvertToBool<T> =
    T extends Primitive ? boolean :
    T extends (infer U)[] ? ConvertToBool<U>[] : // <-- Problem Line
    {[K in keyof T]: ConvertToBool<T[K]>};

但是由于类型别名不能循环引用自身,所以这是行不通的。有谁知道自动转换任意嵌套数组类型的解决方法?

【问题讨论】:

    标签: arrays typescript


    【解决方案1】:

    是的,这是一个已知的限制,但它专门为Array&lt;&gt; 之类的东西提供了解决方法,即interface。从@ahejlsbergpull request introducing conditional typesDeepReadonly&lt;T&gt;的定义:

    type DeepReadonly<T> =
        T extends any[] ? DeepReadonlyArray<T[number]> :
        T extends object ? DeepReadonlyObject<T> :
        T;
    
    interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}
    
    type DeepReadonlyObject<T> = {
        readonly [P in NonFunctionPropertyNames<T>]: DeepReadonly<T[P]>;
    };
    

    如文所述:

    类似于联合和交集类型,条件类型不允许递归引用自己(但是,允许通过接口类型或对象字面量类型进行间接引用 [强调我的],如上面的 DeepReadonly&lt;T&gt; 示例所示)。


    因此,对于您的情况,我们可以这样做:

    type Primitive = string | number | boolean | null | undefined;
    
    interface ConvertToBoolArray<T> extends Array<ConvertToBool<T>> {}
    
    type ConvertToBool<T> =
      T extends Primitive ? boolean :
      T extends (infer U)[] ? ConvertToBoolArray<U> : // okay now
      { [K in keyof T]: ConvertToBool<T[K]> };
    

    让我们看看它是否有效:

    declare const c: ConvertToBool<{ a: number, b: string[], c: { d: number }[] }>;
    c.a // boolean
    c.b[2] // boolean
    c.c[3].d // boolean
    
    type BoolBoolBool = ConvertToBool<number[][][]>
    declare const bbb: BoolBoolBool;
    bbb[0][1][2] === true; // okeydokey
    

    这可行,但需要注意的是,BoolBoolBool 在检查时看起来不像 boolean[][][];它是ConvertToBoolArray&lt;number[][]&gt;,但它们是等价的:

    type IsSame<T extends V, U extends T, V=U> = true;
    // IsSame<T, U> only compiles if T extends U and U extends T:
    
    declare const sameWitness: IsSame<BoolBoolBool, boolean[][][]> // works
    

    希望有所帮助;祝你好运!

    【讨论】:

      【解决方案2】:

      我使用@jcalz(谢谢)提到的相同技术将任何日期转换为字符串,效果非常好

          type PrimitiveType = string | number | boolean | null | undefined | never;
          export type ConvertDateToString<T> =
             T extends Date ? string :
             T extends PrimitiveType ? T :
             T extends Array<infer U> ? Array<ConvertDateToString<U>> :
             { [K in keyof T]: ConvertDateToString<T[K]> };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-10-14
        • 2021-10-03
        • 2012-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-29
        • 1970-01-01
        相关资源
        最近更新 更多