如何使用可选类型定义自引用可扩展接口?

时间:2018-12-24 11:50:13

标签: typescript generics

假设我有菜单界面:

interface IMenuBase {
    id: number;
    title: string;
    items: IMenuBase[]; <- children 
}

现在我想扩展它。为此,我定义了另一个接口:

interface ICustomMenu extend IMenuBase {
    concrete: string;
}

问题在于,items仍然是IMenuBase。

我试图通过这种方式解决它:

interface IMenuBase<T extends IMenuBase<T>> {
    id: number;
    title: string;
    items: T[];
}

interface ICustomMenu extends IMenuBase<ICustomMenu> {
    concrete: string;
}

但是现在我希望能够不带类型地使用IMenuBase。 这是我的playground

1 个答案:

答案 0 :(得分:1)

您有两种可能。您可以采用当前使基类通用的解决方案,并为type参数添加默认值:

interface IMenuBase<T extends IMenuBase<T> = IMenuBase<T>> {
    id: number;
    title: string;
    items: T[];
}

interface ICustomMenu extends IMenuBase<ICustomMenu> {
    concrete: string;
}

const testBase = {} as IMenuBase;
testBase.items[0].items[0].id;

const testConcrete = {} as ICustomMenu;
testConcrete.items[0].items[0].concrete;

上面的代码有一个问题,它仅适用于3个级别(我认为默认值的递归性受编译器的限制)

一个更好的选择可能是使用多态this来指定子代与当前类型属于同一类型,无论该类型是什么:

interface IMenuBase {
    id: number;
    title: string;
    items: this[];
}

interface ICustomMenu extends IMenuBase {
    concrete: string;
}

const testBase = {} as IMenuBase;
testBase.items[0].items[0].id;

const testConcrete = {} as ICustomMenu;
testConcrete.items[0].items[0].concrete;