Машинопись - как расширить интерфейс в определенном месте (расширить базовое состояние для библиотеки xstate)

Я хочу иметь возможность расширить базовый интерфейс в одном или нескольких конкретных местах. Идея состоит в том, чтобы иметь возможность определить базовое состояние для библиотеки xstate, которое может быть расширено для более конкретных целей.

у меня есть

interface Base {
   id:string;
   states:{
       init:{},
       loading:{},
       idle:{
            states:{
                  someBaseState:{}
            }

       }
   }
}

Я хочу знать, возможно ли с машинописью расширить базовый интерфейс в определенном месте. например, свойство "простоя"

interface Page "extends Base Idle Property" {
   id:string;
   states:{
       someOtherState:{}
   }
}

так что результат

{
   id:string;
   states:{
       init:{},
       loading:{},
       idle:{
            id:string;
            states:{
                someBaseState:{}
                someOtherState:{}
            }
       }
   }
}

Я знаю, что могу определить общий в Typescript, как это

interface Base<T> {
  id: string;
  states: {
    idle: T
  }
}

Но я хочу иметь возможность определять конкретные базовые свойства для состояния "простоя" (например) и не реализовывать его каждый раз полностью.

1 ответ

Учитывая эти определения:

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;
        };
    };
}

В любом случае должно работать. Надеюсь, это поможет; удачи!

Ссылка на код

Другие вопросы по тегам