Typescript 扩展通用接口

问题描述 投票:0回答:2

我想创建一个接口,通过该接口我可以扩展任何打字稿类型以添加属性来扩展泛型类型。例如,创建一个如下所示的

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
}

这似乎完成了我想做的事情,尽管我觉得我这样做是在作弊。

我认识到如果我覆盖泛型类型的属性,这种“反向扩展”可能会出现问题,但这是唯一的问题吗?我无法理解这个问题,创建仅添加属性的类型的最佳方法是什么?

typescript inheritance typescript-generics
2个回答
11
投票

有一个长期存在的功能请求,microsoft/TypeScript#2225,它要求能够按照您要求的方式执行

interface Foo<T> extends T {...}
。 它尚未实现(并且可能永远不会实现)。 现在你只能创建一个接口,该接口是
extends
具有静态已知键的对象类型。 未指定的泛型类型参数
T
不起作用,因为编译器无法预测它将具有哪些键。

您应该放心,交集是实现此目的的合理方法(需要注意的是,如果您添加的属性与

T
的属性冲突,您不会收到警告,正如您所注意到的)。 这是上述功能请求中的建议解决方案。 此外,Object.assign()
TypeScript库types
使用交集来表示向现有对象添加属性的结果的类型。 因此,
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

看起来不错。

Playground 代码链接


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 };
© www.soinside.com 2019 - 2024. All rights reserved.