如何合并两个接口类型并将重叠属性的类型合并?

问题描述 投票:0回答:1

如何编写一个泛型类型别名

Combine<A, B>
,它组合了任意两个接口 A 和 B,同时保持两个接口的匹配属性,但使用 union 合并属性类型?

以这两个接口为例:

interface Interface1 {
  type: string;
  another: bool;
}
interface Interface2 {
  type: number;
}

然后

Combine<Interface1, Interface2>
应评估为以下类型:

type Result = {
  type: string | number;
  another: bool;
}
typescript
1个回答
8
投票

首先获取 A 中不在 B 中的所有键,以及 B 中不在 A 中的键,并且对于键的交集显式定义并集:

type Combine<A, B> = 
    Omit<A, keyof B> // items in A that aren't in B
  & Omit<B, keyof A> // items in B that aren't in A
  & { [K in keyof A & keyof B]: A[K] | B[K] }; // union of both.

请注意,指示一个中存在但另一个中不存在的键可能不存在可能会有所帮助,因此您可以在

Partial
上使用
Omit

type Combine<A, B> = 
    Partial<Omit<A, keyof B>> // possibly items in A that aren't in B
  & Partial<Omit<B, keyof A>> // possibly items in B that aren't in A
  & { [K in keyof A & keyof B]: A[K] | B[K] }; // union of both.

编辑:Aarium 询问使用联合的问题让我找到了一种更好的方法,因为

T extends any ? X : never
将对联合的每个元素进行操作,您实际上可以扩展联合的任何元素中存在的所有键,然后创建一个与所有接口对应的值的并集,因此归结为:

// gets all viable keys from all interfaces in a union.
type AllKeysOf<T> = T extends any ? keyof T : never
// basically does T[K] but when T is a union it only gives T[K] for the members of the union for which it is a valid key.
type Get<T, K extends keyof any, Fallback=never> = T extends Record<K, any> ? T[K] : Fallback
// takes a union of interfaces and merges them so that any common key is a union of possibilities.
type Combine< T,
    setThisToUndefinedToProperlyHandleOptionalFields = never
  > = {[K in AllKeysOf<T>]: Get<T,K, setThisToUndefinedToProperlyHandleOptionalFields>}


type TEST = Combine<{a:1} | {a:2, b:10} | {b: 11}>
// TEST = {a: 1|2, b: 10|11}

type TEST2 = Combine<{a:1,b:10} | {a:2},undefined>
// TEST2 = { a: 1|2, b: 10|undefined }

请注意,如果您将

Fallback
中的
Get
generic 设置为
never
,它只会忽略未定义该键的联合元素,但您可以将其设置为
undefined
以指示已定义的键在某些接口中,但并非所有接口最终都可能是未定义的,并不完全说它是可选的,但非常接近。不同处理的确切含义很大程度上取决于您的具体用例,因此我不会在这里详细介绍。 (只需尝试
never
undefined
,看看哪一个能提供您想要的行为)

© www.soinside.com 2019 - 2024. All rights reserved.