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

How to declare an optional generic type in an interface?

我有这个界面:

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 那么我假设我想要访问数据,如果没有则假设它不存在。可能吗?

你可以试试这个

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;
}

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

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

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: ""
};

为了实现这一点,我们需要使用条件类型。

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 是由类型构造函数的参数给出的类型。还要清除信息 - 类型构造函数 = 任何带有泛型参数的类型定义。