如何在接口中声明可选的泛型类型?

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 id: AlertId;数据?:T;按钮标识:警报按钮标识; 。那么我们应该能够在不声明类型的情况下使用接口 非常好的实现。你真的帮了我!【参考方案2】:

创建第二个包装类型,当它提供一个类型时它不会省略数据,但当没有提供类型时,则省略数据字段。

正如您所说,将数据设为可选并不是正确的做法,因为您需要该字段在您不需要时根本不存在。

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;

【讨论】:

&lt;T = any&gt; 的问题是,如果我执行x.,我仍然会得到data 作为自动完成功能。 您必须将它们分成两个接口,并像第二种解决方案一样在他的情况下使用每个接口

以上是关于如何在接口中声明可选的泛型类型?的主要内容,如果未能解决你的问题,请参考以下文章

Java中的泛型

Java语言中的泛型

Java泛型知识总结篇

如何在流中定义具有指定类型的所有可选字段的泛型类型

受保护的泛型类 - 是不是支持?

当类的泛型相关时,如何在两个泛型类之间创建类似子类型的关系