如何在接口中声明可选的泛型类型?
Posted
技术标签:
【中文标题】如何在接口中声明可选的泛型类型?【英文标题】:How to declare an optional generic type in an interface? 【发布时间】:2020-03-13 02:59:21 【问题描述】:我有这个界面:
export interface AlertInteraction<T>
id: AlertId;
data: T;
buttonId: AlertButtonId;
但有时不需要数据。我知道我可以将其声明为data: T
,但我想知道我是否可以这样:
export interface AlertInteraction<T>
id: AlertId;
data: T;
buttonId: AlertButtonId;
export interface AlertInteraction
id: AlertId;
buttonId: AlertButtonId;
所以,如果我给T
,那么我假设我想访问数据,如果没有,那么假设它不存在。有可能吗?
【问题讨论】:
【参考方案1】:为了实现这一点,我们需要使用条件类型。
type AlertId = string; // just example type alias
type AlertButtonId = string; // just example type alias
type AlertInteraction<T = undefined> =
id: AlertId;
buttonId: AlertButtonId;
& (T extends undefined ? :
data: T;
)
// example usage
// no need for data (T is undefined)
const a: AlertInteraction =
id: '1',
buttonId: '1'
// data prop is required
const b: AlertInteraction<number> =
id: '1',
data: 1,
buttonId: '1'
最重要的是这部分:
& (T extends undefined ? :
data: T;
)
如果 T 可分配给未定义,我们有条件地加入或输入,或者我们为其他类型加入
data: T
。结果如果我们不设置泛型,默认为undefined
,我们的类型构造函数计算为:
// For T == undefined
id: AlertId;
buttonId: AlertButtonId;
&
// what is equal to just:
id: AlertId;
buttonId: AlertButtonId;
如果提供的参数(通用)与undefined
不同,那么最终类型具有以下形式:
// For T != undefined
id: AlertId;
buttonId: AlertButtonId;
& data: T
// which is equal to
id: AlertId;
buttonId: AlertButtonId;
data: T;
其中T
是由类型构造函数的参数给出的类型。还要清除信息 - 类型构造函数 = 任何带有泛型参数的类型定义。
【讨论】:
我们不能只写:export interface AlertInteraction创建第二个包装类型,当它提供一个类型时它不会省略数据,但当没有提供类型时,则省略数据字段。
正如您所说,将数据设为可选并不是正确的做法,因为您需要该字段在您不需要时根本不存在。
export interface IInterationData<T>
id: AlertId;
data: T;
buttonId: AlertButtonId;
type IAlertInteraction<T = undefined> = T extends undefined
? Omit<IInterationData<any>, "data">
: IInterationData<T>;
export const a: IAlertInteraction =
id: 1,
buttonId: ""
;
export const b: IAlertInteraction<number> =
id: 1,
data: 2,
buttonId: ""
;
【讨论】:
【参考方案3】:你可以试试这样的
export interface AlertInteraction<T = any>
id: AlertId;
data?: T;
buttonId: AlertButtonId;
// those are valid:
const x: AlertInteraction = id: 'AlertId', buttonId: 'AlertButtonId';
// Accept the data property as number only.
const x: AlertInteraction<number> = id: 'AlertId', buttonId: 'AlertButtonId', data: 123;
或者你可以让它们成为 2 个接口,一个没有 data
属性和通用参数,第二个扩展第一个并具有数据属性和通用参数
类似的东西
export interface AlertInteractionBase
id: string;
buttonId: string;
export interface AlertInteraction<T> extends AlertInteractionBase
data: T;
【讨论】:
<T = any>
的问题是,如果我执行x.
,我仍然会得到data
作为自动完成功能。
您必须将它们分成两个接口,并像第二种解决方案一样在他的情况下使用每个接口以上是关于如何在接口中声明可选的泛型类型?的主要内容,如果未能解决你的问题,请参考以下文章