gpt4 book ai didi

仅具有使用特定模板参数值定义的属性的 TypeScript 通用接口(interface)

转载 作者:行者123 更新时间:2023-12-05 03:00:00 27 4
gpt4 key购买 nike

我有一个通用接口(interface),其中 T延伸boolean .如果T延伸true ,我希望一个属性存在,否则,我不希望它存在。这个接口(interface)扩展了另一个接口(interface),所以我不能使用一个类型,我不想使用多个接口(interface)和一个联合类型。

我曾希望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'
};

我也尝试同时使用 voidundefined .在这三种情况下,当我实例化 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;

这是 TypeScript Playground .

最佳答案

解决方法

// 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,但您几乎可以互换使用类型和接口(interface)。


让事情变得更好

为了使整个事情更好用,我建议将“有条件地提取属性”的过程提取到一个可以重复使用的单独类型中。

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{},因此它会有条件地添加什么都不做的 {},或者包括您希望包含在其中的属性 - 取决于您传入的内容。

然后我会用它来扩展接口(interface),比如:

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
}

但这会给你以下错误:

接口(interface)只能扩展对象类型或对象类型与静态已知成员的交集。

而且没有办法绕过这个错误:Typescript 无法知道要静态包含什么,所以它不允许它。

关于仅具有使用特定模板参数值定义的属性的 TypeScript 通用接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57381624/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com