node.js - TypeScript:通用接口作为其他接口的联合
问题描述
我想创建一个通用接口,其属性代表来自其他接口的属性的联合。
假设我有两个接口
interface A {
something: string;
somethingElse: number;
}
interface B {
something: Array<string>;
}
我不想把界面C
写成
interface C {
something: string | Array<string>;
somethingElse?: number;
}
因为这意味着每当我修改任何一个接口时A
,B
我都需要手动修改接口C
。
根据我在 TypeScript 文档中看到的内容以及 Stack Overflow 上的答案,我应该声明一个新类型
type unionOfKeys = keyof A | keyof B;
并实现通用接口形式
interface GenericInterface {
<T>(arg: T): T;
}
我在想的方向
interface C {
<T extends unionOfKeys>(arg: T): T extends unionOfKeys ? A[T] | B[T] : any
}
但由于许多属性及其类型之间的不匹配而失败。
我将不胜感激任何形式的帮助。谢谢你。
解决方案
我认为以下版本的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; }
// }
这与另一个答案相似,因为它找到T
(称为它UnionKeys
,定义为T extends any ? keyof T : never
)的所有成分的所有键的并集,并返回一个包含所有成分的映射类型。不同的是,这里我们还找到了所有成分的所有键的交集T
(称为它IntersectKeys
,定义为just 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; }
我没有一个更复杂的答案,所以我会在这里停下来。
也许这足以满足您的需求。或者@TitianCernicova-Dragomir 的回答可能足以满足您的需求。希望这些答案对您有所帮助;祝你好运!
推荐阅读
- javascript - 如何将图像 url 从 firebase 显示到 html 表中?
- sql - 使用上一行的值和下一行的值计算平均值
- android - 安卓服务是否会因为从不安全的网络从 Play 商店下载应用程序而被黑客入侵
- java - 在 Java 中锁定文件通道时出现 OverlappingFileLockException
- javascript - img.onload 在新的 Image() 声明后拒绝触发
- asp.net-core - 如何使用 Swashbuckle.AspNetCore v5.0.0-rc2 记录 API 密钥身份验证
- c++ - 将子变量传递给父构造函数
- apache-spark - 火花高阶函数变换输出结构
- c# - 打开 xml 2.5 查找具有特定字段代码的特定占位符。C#
- sql - 如何使用 linq 从数据库中检索数据?