typescript - 使用 TypeScript 泛型作为自己的参数,或将其指定为自己的默认参数
问题描述
我有以下接口和从它扩展的ItemBase
多个其他递归接口:xItem
interface ItemBase<Children extends ItemBase<Children>> {
x: string;
y: number;
children: Children[];
}
interface FooItem extends ItemBase<FooItem> {
foo: boolean;
}
interface BarItem extends ItemBase<BarItem> {
bar: "b" | "a" | "r";
}
我现在想引用ItemBase
它自己作为它自己的论点:
const transformItem = (item: ItemBase<ItemBase>) => { ... }
// ^
// TS2314: Generic type 'ItemBase ' requires 1 type argument(s).
但这不起作用,因为我没有指定 innerItemBase
的参数(并且显然不能继续将这些参数指定为无穷大)。
更好的是提供自己作为ItemBase
默认参数...我尝试了两种方法,但每种方法都遇到了自己的错误:
interface ItemBase<Children extends ItemBase<Children> = ItemBase<Children>> {
// ^
// TS2744: Type parameter defaults can only reference previously declared type parameters.
x: string;
y: number;
children: Children[];
}
interface ItemBase<Children extends ItemBase<Children> = ItemBase> {
// ^
// TS2716: Type parameter 'Children' has a circular default.
x: string;
y: number;
children: Children[];
}
一个明显的解决方法是创建一个单独的接口来表达我的自引用基础:
interface BaseItem extends ItemBase<BaseItem> {}
const transformItem = (item: BaseItem) => { ... }
但这更像是一种技巧,因为其他项目并没有真正继承自它。
我还有哪些其他选择?
解决方案
根据您的用例,您可能想要使用多态this
类型。在interface
orclass
声明中,您可以使用命名的类型this
来引用“当前”子类型。好像this
是一个“隐式”泛型类型参数,其行为 类似于. 它使您不必显式使用泛型:interface Foo<T extends Foo<T>>
interface ItemBase {
x: string;
y: number;
children: this[];
}
interface FooItem extends ItemBase {
foo: boolean;
}
interface BarItem extends ItemBase {
bar: "b" | "a" | "r";
}
为了看到它的实际效果,这里有一些可能的用途:
const fooItem: FooItem = {
x: "a",
y: 1,
foo: true,
children: [{
x: "b", y: 2, foo: true, children: []
}]
}
function processItem(item: ItemBase) {
console.log(item.x.toUpperCase());
console.log(item.y.toFixed(2));
item.children.forEach(i => processItem(i));
}
processItem(fooItem); // A, 1,00, B, 2.00
在某些情况下,多态this
很难使用,但在问题中没有更具体的用例,我不确定您是否会遇到它们。