Typescript 扩展泛型接口

5

我希望创建一个接口,可以扩展任何 TypeScript 类型,并添加一个属性以扩展泛型类型。例如,创建一个类似于下面的 Confidence<any> 类型:

export interface Confidence<T> extends T{
   confidenceLevel:number
}

然后可以通过以下方式进行访问:

const date:Confidence<Date> = new Date();
date.confidenceLevel = .9;

这似乎不可能实现(而且我感觉这是反模式),但我可以做。
export type Confidence<T> = T & {
   confidenceLevel:number
}

看起来这似乎能实现我的需求,但是我感觉这样做有些作弊。

我知道如果我重写泛型类型的属性,这种“反向扩展”可能会出问题,但这是唯一需要考虑的吗?我对此感到困惑,有什么好的方法可以创建一个仅添加属性的类型呢?

2个回答

11

有一个长期存在的功能请求,microsoft/TypeScript#2225,它要求能够像您所要求的那样执行interface Foo<T> extends T {...}。目前尚未实现(可能永远不会)。现在,您只能创建一个接口,该接口extends具有静态已知键的对象类型。未指定的泛型类型参数T无法工作,因为编译器无法预测它将具有哪些键。

您应该放心,intersection是实现此目的的合理方法(请注意,如果您添加的属性与T的属性冲突,您将不会收到警告,就像您注意到的那样)。这是上述功能请求中suggested的解决方案。此外,TypeScript library typings for Object.assign()使用交集来表示向现有对象添加属性的结果类型。因此,使用定义为Confidence<T>的内容如下:

type Confidence<T> = T & {
  confidenceLevel: number
}

你可以轻松编写一个生成这些之一的函数,如下所示:

function makeConfidence<T>(x: T, confidenceLevel: number): Confidence<T> {
  return Object.assign(x, { confidenceLevel });
}

并使用它:

const x = makeConfidence(new Date(), 0.9); // x is a Confidence<Date>;
console.log(x.getFullYear()); // 2020
console.log(x.confidenceLevel); 0.9

看起来很不错。好的,希望能帮到你;祝你好运!

代码的游乐场链接


感谢您进行健全性检查并提醒这是一个请求的功能!我有点困惑于接口和类型之间的区别,但我想我会把它留到另一天再说。 - BobtheMagicMoose
如果 T 是一个可选类型,例如 type Confidence<T = never> = T & {...},这将返回未定义而不是其余的 {...},有什么办法可以解决这个问题吗? - Ricardo Dias Morais
20分钟后找到了一个解决方案,我会发布出来以便有需要的人。 - Ricardo Dias Morais

1

jcalz的答案扩展:

如果您想使泛型类型T可选,可以将其扩展自Record<string, unknown>并将值设置为Record<string, unknown>

type Confidence<
  T extends Record<string, unknown> = Record<string, unknown>
> = T & {
  confidenceLevel: number
};

然后,如果需要,您将能够无需任何通用代码使用它:

interface Bar {
  barLevel: number
};

const foo: Confidence = { confidenceLevel: 100 };
const bar: Confidence<Bar> = { confidenceLevel: 100, barLevel: 2 };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接