【问题标题】:Typescript generics: readonly values from interface children打字稿泛型:来自接口子级的只读值
【发布时间】:2021-09-27 04:36:06
【问题描述】:

鉴于此输入:

export type Test = {
    one: {
        a: string;
        b: string;
        c: string;
    };
    two: {
        a: string;
        b: string;
        d: string;
    };
}

我需要像CombinedChildren<T> 这样的泛型,它输出以下类型:

export type Combined = {
    a?: string;
    b?: string;
    c?: string;
    d?: string;
}

基本上,它获取子属性并将它们组合起来,包括它们,即使它们并非存在于所有子元素中

试过

export type KeyOfTest = Partial<Test[keyof Test]>
export type MappedKeyOfTest = Partial<{
    [key in keyof Test[keyof Test]]: Test[keyof Test][key]
}>

但没有一个输出完全符合我的要求。

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    我们可以将其分解为几个步骤。首先,我们通过Test[keyof Test] 得到所有子类型的联合。然后我们想要一个所有这种类型的联合,所以我们使用一种将联合类型转换为交集类型的实用程序类型 (taken from this answer by @jcalz)。最后,我们将Partial 应用于结果类型。

    export type Test = {
        one: {
            a: string;
            b: string;
            c: string;
        };
        two: {
            a: string;
            b: string;
            d: string;
        };
        three: {
          a: string;
          e: number;
        }
    }
    
    // union to intersection converter by @jcalz: https://stackoverflow.com/a/50375286/8580499
    // Intersect<{ a: 1 } | { b: 2 }> = { a: 1 } & { b: 2 }
    type Intersect<T> = (T extends any ? ((x: T) => 0) : never) extends ((x: infer R) => 0) ? R : never;
    
    // Combined = { a?: string; b?: string; c?: string; d?: string; e?: number }
    type Combined = Partial<Intersect<Test[keyof Test]>>;
    

    Playground link

    【讨论】:

    • 由于类型之间的冲突,这可能无法按预期工作。例如,尝试将 a 的第二个对象类型更改为数字。结果将是一个?:未定义
    • @ZZB 如果没有更详细的规范,我认为在这种情况下没有任何合理的输出。我们要a?: string | number 还是省略a 或别的什么?
    • 如果看到像“字符串”这样的合并类型的答案会很有趣| “数字”。我尝试过这样做,但结果比我想象的要棘手
    • 这里是这个问题的答案stackoverflow.com/questions/56296506/…
    【解决方案2】:

    如果您还想合并所有类型,例如字符串 |数字然后这是一个解决方案

    export type Test = {
        one: {
            a: string;
            b: string;
            c: string;
        };
        two: {
            a: number;
            b: string;
            d: string;
        };
        three: {
          a: string;
          e: number;
        }
    }
    
    type AllNested = Test[keyof Test]
    
    type KeyOf<T> = T extends any ? keyof T : never
    
    type PropValue<T, K extends PropertyKey> = T extends Record<K, infer V> ? V : never
    
    type Merged<T> = {
        [P in KeyOf<T>] : PropValue<T, P>
    }
    
    type MergedType = Merged<AllNested>
    

    链接到 playground

    解决方案基于这个出色的answer

    【讨论】:

      猜你喜欢
      • 2017-09-26
      • 2018-12-27
      • 2018-01-18
      • 2021-05-15
      • 1970-01-01
      • 1970-01-01
      • 2020-05-09
      • 1970-01-01
      • 2015-11-27
      相关资源
      最近更新 更多