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

时间:2019-02-08 19:04:30

标签: typescript

给出一种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 个答案:

答案 0 :(得分:3)

我不知道您希望嵌套的深度,但是您可能想要这样的东西:

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,或者遍历{{ 1}}或T并合并得更深。它如何确定哪些属性应该是可选的以及如何确定何时停止合并的细节很简单,但解释起来很繁琐。如果您需要详细说明的内容,请告诉我。

您可以验证U等于

PersonModified

根据需要。

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

答案 1 :(得分:0)

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

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>;