代码之家  ›  专栏  ›  技术社区  ›  ThomasReggi

创建具有覆盖属性的接口的泛型

  •  1
  • ThomasReggi  · 技术社区  · 5 年前

    给定 Person 类型

    type Person = {
      name: string,
      age: number,
      address: {
        line1: string,
        line2: string | null | number,
        zip: string | number,
      },
    };
    

    我想应用覆盖并修改此界面。

    type PersonOverwrites = {
      address: {
        line2?: string,
        zip: string,
      },
    };
    

    我想从这两个界面创建以下内容:

    type PersonModified = {
      name: string,
      age: number,
      address: {
        line1: string,
        line2?: string,
        zip: string,
      },
    }
    

    这就是我要找的:

    type PersonModified = Overwrite<Person, PersonOverwrites>
    

    如何创建这种类型的泛型?

    使现代化

    应投诉:

    type DeepMerge<T, U> = [T, U] extends [object, object] ?
      {
        [K in keyof (U & Pick<T, Exclude<keyof T, keyof U>>)]: (
          K extends keyof U ? (
            K extends keyof T ? DeepMerge<T[K], U[K]> : U[K]
          ) : (
            K extends keyof T ? T[K] : never
          )
        )
      } : U;
    
    
    type Person = {
      name: string,
      age: number,
      address: {
        line1: string,
        line2: string | null | number,
        zip: string | number,
        address?: {
            line1: string,
            line2: string | null | number,
            zip: string | number,
            address?: {
                line1: string,
                line2: string | null | number,
                zip: string | number,
            },
        },
      },
    };
    
    type PersonOverwrites = {
        address: {
            line2?: string,
            zip: string,
            address?: {
                address: {
                    pizzaDelivery: boolean,
                },
            },
        },
    };
    
    const person: Person = {
        name: 'Thomas',
        age: 12,
        address: {
            line1: 'hi',
            line2: 'hi',
            zip: 'hi',
            address: {
                line1: 'hi',
                line2: 'hi',
                zip: 'hi',
                address: {
                    line1: 'hi',
                    line2: 'hi',
                    zip: 'hi',
                    // pizzaDelivery: true,
                }
            }
        }
    }
    
    2 回复  |  直到 5 年前
        1
  •  3
  •   jcalz    5 年前

    我不知道你希望这个嵌套得有多深,但你可能想要这样的东西:

    type DeepMerge<T, U> = [T, U] extends [object, object] ?
      {
        [K in keyof (U & Pick<T, Exclude<keyof T, keyof U>>)]: (
          K extends keyof U ? (
            K extends keyof T ? DeepMerge<T[K], U[K]> : U[K]
          ) : (
            K extends keyof T ? T[K] : never
          )
        )
      } : U;
    
    type PersonModified = DeepMerge<Person, PersonOverwrites>
    

    我们的想法是 DeepMerge<T, U> 计算结果为 U 如果其中一个 T U 不是对象类型,或者它遍历 T U 并更深入地融合。关于它如何确定哪些属性应该是可选的,以及它如何决定何时停止合并的细节很简单,但很难解释。如果你需要一些具体的细节,请告诉我。

    您可以验证 PersonModified 相当于

    type PersonModified = {
        address: {
            line2?: string | undefined;
            zip: string;
            line1: string;
        };
        name: string;
        age: number;
    }
    

    如你所愿。

    希望有帮助;祝你好运

        2
  •  0
  •   ThomasReggi    5 年前

    构建@jcalz answer我相信这可以解决可选问题。

    type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
    
    type DeepMerge<T, U> = [T, U] extends [object, object] ?
      {
        [K in keyof (Merge<T, U>)]: (
          K extends keyof U ? (
            K extends keyof T ? DeepMerge<T[K], U[K]> : U[K]
          ) : (
            K extends keyof T ? T[K] : never
          )
        )
      } : Merge<T, U>;