С учетом этих определений:
interface Base {
id: string;
states: {
init: {};
loading: {};
idle: {
states: {
someBaseState: {};
};
};
};
}
interface Page {
id: string;
states: {
someOtherState: {};
};
}
Самое простое, что можно сделать, это использовать пересечение вместо наследования, например:
type MyNewType = Base & { states: { idle: Page } };
interface MyNewInterface extends MyNewType {} // if you want in interface
Вы можете видеть, что он соответствует желаемой форме:
function foo(mni: MyNewInterface) {
mni.states.init; // okay
mni.states.idle.id; // okay
mni.states.idle.states.someBaseState; // okay
mni.states.idle.states.someOtherState; // okay
}
Этот тип может быть немного трудным для понимания как пересечение ... если вы действительно хотите, вы можете использовать вложенный сопоставленный тип , например:
type NestedId<T> = T extends object ? { [K in keyof T]: NestedId<T[K]> } : T;
type NestedExtend<T, U> = NestedId<T & U>;
type MyNewType2 = NestedExtend<Base, { states: { idle: Page } }>;
, который показывает следующий тип при проверке через IntelliSense:
// IntelliSense shows you
type MyNewType2 = {
id: string;
states: {
init: {};
loading: {};
idle: {
states: {
someBaseState: {};
someOtherState: {};
};
id: string;
};
};
}
В любом случае должно работать. Надеюсь, это поможет; удачи!
Ссылка на код