TypeScript:通用接口作为其他接口的联合

4 generics interface node.js typescript

我想创建一个通用接口,其属性代表其他接口的属性的联合。

假设我有两个接口

interface A {
    something: string;
    somethingElse: number;
}

interface B {
    something: Array<string>;
}
Run Code Online (Sandbox Code Playgroud)

我不想将接口写C

interface C {
    something: string | Array<string>;
    somethingElse?: number;
}
Run Code Online (Sandbox Code Playgroud)

因为这意味着每当我修改接口A或时,我也B需要手动修改接口。C

根据我在 TypeScript 文档以及 Stack Overflow 上的答案中看到的内容,我应该声明一个新类型

type unionOfKeys = keyof A | keyof B;
Run Code Online (Sandbox Code Playgroud)

并实现通用接口形式

interface GenericInterface {
    <T>(arg: T): T;
}
Run Code Online (Sandbox Code Playgroud)

我当时的想法是

interface C {
    <T extends unionOfKeys>(arg: T): T extends unionOfKeys ? A[T] | B[T] : any
}
Run Code Online (Sandbox Code Playgroud)

但这会失败,因为许多属性及其类型之间不匹配。

我将不胜感激任何形式的帮助。谢谢。

jca*_*alz 5

我认为以下版本MergeUnion<T>可能会按照您想要的方式运行:

type MergeUnion<T> = (
  keyof T extends infer K ? [K] extends [keyof T] ? Pick<T, K> & {
    [P in Exclude<(T extends any ? keyof T : never), K>]?:
    T extends Partial<Record<P, infer V>> ? V : never
  } : never : never
) extends infer U ? { [K in keyof U]: U[K] } : never;

type C = MergeUnion<A | B>;
// type C = { 
//  something: string | string[]; 
//  somethingElse?: number | undefined; }
// }
Run Code Online (Sandbox Code Playgroud)

这与另一个答案类似,因为它找到 的所有成分的所有键的并集T(称为UnionKeys,定义为T extends any ? keyof T : never)并返回包含所有这些成分的映射类型。不同的是,这里我们还找到 的所有成分的所有键的交集T(称为IntersectKeys,定义为keyof T),并将这些键分成T两组键。交集的属性存在于每个成分中,因此我们只需要做即可Pick<T, IntesectKeys>获得公共属性。余下的Exclude<UnionKeys, IntersectKeys> 在最终类型中是可选的。

更新 2019-08-23:下面提到的错误似乎从 TS3.5.1 开始已修复

它非常丑陋,如果我感觉好点的话我会清理它。问题是,当所有成分中出现的任何属性本身都是可选的时,仍然存在问题。TypeScript 中存在一个错误(从 TS3.5 开始),在 中{a?: string} | {a?: number},该a属性被视为必需属性,如{a: string | number | undefined},而如果任何组成部分将其视为可选属性,则将其视为可选属性会更正确。该错误渗透到MergeUnion

type Oops = MergeUnion<{a?: string} | {a?: number}>
// type Oops =  { a: string | number | undefined; }
Run Code Online (Sandbox Code Playgroud)

我没有一个不是更复杂的很好的答案,所以我就到此为止。

也许这足以满足您的需求。或者也许@TitianCernicova-Dragomir 的答案足以满足您的需求。希望这些回答对您有所帮助;祝你好运!

链接到代码