我想创建一个接口,通过该接口我可以扩展任何打字稿类型以添加属性来扩展泛型类型。例如,创建一个如下所示的
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
}
这似乎完成了我想做的事情,尽管我觉得我这样做是在作弊。
我认识到如果我覆盖泛型类型的属性,这种“反向扩展”可能会出现问题,但这是唯一的问题吗?我无法理解这个问题,创建仅添加属性的类型的最佳方法是什么?
有一个长期存在的功能请求,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
看起来不错。
从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 };