最近我遇到了类似这样的东西:
interface Test<T extends Test<T>> {
a: number;
b: T;
}
function foo <T extends Test<T>>(el: T): T {
...
}
我必须说我有点困惑这是什么,以及为什么需要这样的东西。我已经阅读了Typescript手册中的泛型部分,但没有找到类似的内容。
那个接口实现了什么,不能用以下内容实现吗?
interface Test<T>
有人能解释一下这个吗?
最近我遇到了类似这样的东西:
interface Test<T extends Test<T>> {
a: number;
b: T;
}
function foo <T extends Test<T>>(el: T): T {
...
}
interface Test<T>
有人能解释一下这个吗?
没有实际的例子,我只能讲一些概念。在像Java这样没有多态 this
类型的语言中,你需要这种语法。
这个概念是你想要一个泛型类型,它指向其包含类或接口的其他对象,这些对象与其具有相同的类型。让我们看一下你的Test
接口:
interface Test<T extends Test<T>> {
a: number;
b: T;
}
这描述了一种类似于链表的结构,其中 Test<T>
的 b
属性必须也是一个 Test<T>
,因为 T
扩展了 Test<T>
。但是,此外,它必须是(父对象的)相同类型的子类型。以下是两个实现示例:
interface ChocolateTest extends Test<ChocolateTest> {
flavor: "chocolate";
}
const choc = {a: 0, b: {a: 1, flavor: "chocolate"}, flavor: "chocolate"} as ChocolateTest;
choc.b.b = choc;
interface VanillaTest extends Test<VanillaTest> {
flavor: "vanilla";
}
const vani = {a: 0, b: {a: 1, flavor: "vanilla"}, flavor: "vanilla"} as VanillaTest;
vani.b.b = vani;
ChocolateTest
和VanillaTest
都是Test
的实现,但它们不能互换。 ChocolateTest
的b
属性是ChocolateTest
,而VanillaTest
的b
属性是VanillaTest
。 因此会发生以下错误,这是期望的:
choc.b = vani; // error!
ChocolateTest
时,整个列表都充满了其他的ChocolateTest
实例,而不必担心其他Test
会出现:choc.b.b.b.b.b.b.b.b.b // <-- still a ChocolateTest
将此行为与以下界面进行比较:
interface RelaxedTest {
a: number;
b: RelaxedTest;
}
interface RelaxedChocolateTest extends RelaxedTest {
flavor: "chocolate";
}
const relaxedChoc: RelaxedChocolateTest = choc;
interface RelaxedVanillaTest extends RelaxedTest {
flavor: "vanilla";
}
const relaxedVani: RelaxedVanillaTest = vani;
relaxedChoc.b = relaxedVani; // no error
relaxedChoc.b
的类型是RelaxedTest
,而relaxedVani
与之兼容。而choc.b
的类型是Test<ChocolateTest>
,而vani
与之不兼容。
一种类型约束另一种类型与原始类型相同的能力非常有用。事实上,TypeScript 为此提供了多态this
。您可以将this
用作类型,表示“与包含的类/接口相同的类型”,并且不需要使用上面的泛型内容:
interface BetterTest {
a: number;
b: this; // <-- same as the implementing subtype
}
interface BetterChocolateTest extends BetterTest {
flavor: "chocolate";
}
const betterChoc: BetterChocolateTest = choc;
interface BetterVanillaTest extends BetterTest {
flavor: "vanilla";
}
const betterVani: BetterVanillaTest = vani;
betterChoc.b = betterVani; // error!
Test<T extends Test<T>>
一样,但是没有可能令人费解的循环引用。所以,我建议使用多态的this
,除非你有某些强制要求以另一种方式完成它。this
引入之前编写的代码,或者是由不知道多态的人编写的,或者是否存在我不知道的令人信服的理由。不确定。
希望这有意义并对你有所帮助。祝你好运!
public static foo<TType extends number | string, T extends Tree<TType>>(data: T[]): T[] {
console.log(data[0].key);
return
}
export interface Tree<T> {
label?: string;
data?: any;
parent?: Tree<T>;
parentId?: T;
key?: T;
}