typescript - TypeScript 通用接口,仅具有使用特定模板参数值定义的属性
问题描述
我有一个通用接口,其中T
extends boolean
。如果T
extends true
,我希望一个属性存在,否则,我不希望它存在。这个接口扩展了另一个,所以我不能使用一个类型,我不想使用多个接口和一个联合类型。
我曾希望这never
能解决我的难题。
interface MyInterface<T extends boolean> extends MyOtherInterface {
someProp: string;
conditionalProp: T extends true ? number : never;
}
const cTrue: MyInterface<true> = {
firstProp: 1,
someProp: 'foo',
conditionalProp: 1
},
cFalse: MyInterface<false> = { // fails for missing conditionalProp: never
firstProp: 2,
someProp: 'bar'
},
cAnyTrue: MyInterface<any> = {
firstProp: 3,
someProp: 'baz',
conditionalProp: 3
},
cAnyFalse: MyInterface<any> = { // fails for missing conditionalProp: never
firstProp: 4,
someProp: 'baz'
};
我也尝试同时使用void
和undefined
。在所有三种情况下,当我实例化 时MyInterface<false>
,它都需要设置conditionalProp
。在第一种情况下,我可以将其分配为空,因为它的类型是never
.
就像我之前暗示的那样,有一个冗长的解决方法。
interface MyInterfaceTrue extends MyOtherInterface {
someProp: string;
conditionalProp: number;
}
interface MyInterfaceFalse extends MyOtherInterface {
someProp: string;
}
type MyInterface<T extends boolean> = T extends true ? MyInterfaceTrue : MyInterfaceFalse;
解决方案
解决方法
// The definition of the type with all the properties
interface _Data {
always: number;
sometimes: string;
}
// Conditionally exclude the properties if "true" or "false" was passed.
type Data<T extends boolean> = T extends true ? Omit<_Data, "sometimes"> : _Data;
/*
* Tests
*/
const forTrue: Data<true> = {
always: 0,
// sometimes: "" => Error
};
const forFalse: Data<false> = {
always: 0,
sometimes: ""
}
此解决方案使用 typedef,但您几乎可以互换使用类型和接口。
让事情变得更好
为了使这整个事情更好地使用,我建议将“有条件地提取属性”的过程提取到可以重用的单独类型中。
type ConditionallyOmit<Condition extends boolean, T, K extends keyof T> = Condition extends true ? Omit<T, K> : T;
然后你可以像这样使用它:
type Data<T extends boolean> = ConditionallyOmit<T, _Data, "sometimes">
您当然可以内联原始定义:
type Data<T extends boolean> = ConditionallyOmit<T, {
always: number;
sometimes: string;
}, "sometimes">
这会让它变得尽可能干燥
为什么你需要另一种类型。
我很确定您目前无法仅使用一个界面来执行此操作。
我正在考虑通过扩展一个有条件地包含一个类型的类型来解决这个问题,或者{}
- 类似于以下内容:
type TrueOrEmpty<Condition extends boolean, T> = Condition extends true ? {} : T;
这将为您提供T
or {}
,因此它会有条件地添加{}
不会执行任何操作的或者包含您希望在其中包含的属性 - 取决于您传入的内容。
然后我会用它来扩展接口,比如:
interface Data<T extends boolean>
// Properties you only want when you pass true
extends TrueOrEmpty<T, { sometimes: string }>
{
// Properties you always want to have
always: number
}
但这会给您以下错误:
An interface can only extend an object type or intersection of object types with statically known members.
并且没有办法解决这个错误:Typescript 不知道静态包含什么,所以它不允许它。
推荐阅读
- python - 使用全文在 MongoDB 中进行 Tweepy 流式传输
- python - 如何从python中的散点图中删除空白空间
- r - 按所有行将数据框列表合并到单个数据框
- excel - 如何在 VBA 中循环下面的代码,同时每次降级。当最后一步下降时循环将停止,在单元格中没有值
- graphql - 用苦艾酒在 GraphQL 中表示 Elixir/Ecto 关联
- java - 在 groovy 模板 GSP 中显示链接文本
- python-3.x - cx_freeze - 如何更改对 lib 的引用
- php - 将我的日期输入限制为仅接受 4 个“年份”变量而不是 6 个
- php - 使用 PHP、SQL 和 HTML 从导出的 Excel 表中编辑单元格类型
- python - 在python中将固定点转换为浮点数的问题