Reputation: 1420
Let's say I have menu interface:
interface IMenuBase {
id: number;
title: string;
items: IMenuBase[]; <- children
}
Now I want to extend it. For this purpose I define another interface:
interface ICustomMenu extend IMenuBase {
concrete: string;
}
The probleme is, items
is still an IMenuBase.
I've tried to solve it this way:
interface IMenuBase<T extends IMenuBase<T>> {
id: number;
title: string;
items: T[];
}
interface ICustomMenu extends IMenuBase<ICustomMenu> {
concrete: string;
}
But now I want to be able to use IMenuBase without type. Here is my playground.
Upvotes: 1
Views: 92
Reputation: 250366
You have two possibilities. You can go with your current solution of making the base class generic and add a default for the type parameter:
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;
The above code has the issue that it only works for up to 3 levels (I think this the recursive-ness of the default is limited by the compiler)
A better option might be to use polymorphic this
to specify that the children are of the same type as the current type, whatever that type may be:
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;
Upvotes: 2