Машинопись: Как преобразовать строку в тип

Я создаю кучу веб-компонентов, и каждый из них может генерировать пользовательские события. В качестве примера приведем два простых примера:

//MyButton
emits 'myButtonPressed' and detail of this type:
interface ButtonDetailType {
  id: string;
}

//MySlider
emits 'mySliderChanging' and details of this type:
interface SliderChangingDetailType {
  id: string;
  value: number;
}
emits 'mySliderChanged' and details of this type:
interface SliderChangedDetailType {
  id: string;
  oldValue: number;
  newValue: number;
}

Для прослушивания компонентов у меня есть код, который выглядит следующим образом:

buttonEl.addEventListener( 'myButtonPressed', ( event : CustomEvent ) => {
  const detail = event.detail as ButtonDetailType;
  //now i have access to detail.id
} );

sliderEl.addEventListener( 'mySliderChanging', ( event : CustomEvent ) => {
  const detail = event.detail as SliderChangingDetailType;
  //now i have access to detail.id, detail.value
} );

Поскольку я делаю больше компонентов, у меня возникают трудности с запоминанием всех пользовательских имен событий, которые может испускать каждый компонент, или detailType, который генерирует каждое событие.

Чтобы решить эту проблему, я надеялся создать объект, содержащий всю информацию, подобную этой:

EVENTS = {
  button: {
    myButtonPressed: 'myButtonPressed',
    detailType: 'ButtonDetailType',
  },
  slider: {
    mySliderChanged': 'mySliderChanged',
    detailTypes: {
     'SliderChangedDetailType',
     'SliderChangingDetailType',
    }
  }
};

Теперь у меня есть простой способ получить доступ ко всем именам событий, доступных для каждого компонента, с автозаполнением, помогающим мне в процессе ввода:

buttonEl.addEventListener( EVENTS.button. //autocomplete shows me all event names here! YAY!
sliderEl.addEventListener( EVENTS.slider. //autocomplete here too!

Проблема в том, что я не знаю, как преобразовать строку в тип. Я хотел бы иметь возможность напечатать это:

buttonEl.addEventListener( EVENTS.button.myButtonPressed, ( event : CustomEvent ) => {
  const detail = event.detail as EVENTS.button.detailType; // <- invalid: EVENTS.button.detailType is a string not a type!
} );

Есть ли способ преобразовать строки в типы в TypeScript?

1 ответ

Решение

Вы не можете действительно преобразовать строки в типы без отображения. На самом деле, вы действительно не хотите, чтобы эти строки были первыми, за исключением фактической строки, переданной в addEventListener() как type параметр. Кажется, что вы действительно хотите что-то вроде пространств имен или модулей для организации ваших типов.

Например, используя пространства имен, мы можем получить что-то похожее на EVENTS объект, за исключением того, что вместо ссылки только на строковые значения, он ссылается на строковые значения и типы:

namespace EVENTS {
  export namespace button {
    export const myButtonPressed = "myButtonPressed";
    export namespace detailType {
      export interface ButtonDetailType {
        id: string;
      }
    }
  }
  export namespace slider {
    export const mySliderChanged = "mySliderChanged";
    export namespace detailTypes {
      export interface SliderChangingDetailType {
        id: string;
        value: number;
      }
      export interface SliderChangedDetailType {
        id: string;
        oldValue: number;
        newValue: number;
      }
    }
  }
}

Это должно дать вам те же автозаполнения, которые вы видели ранее, плюс те для типов:

buttonEl.addEventListener(EVENTS.button.myButtonPressed, ((event: CustomEvent) => {
  const detail = event.detail as EVENTS.button.detailType.ButtonDetailType;
}) as EventListener);

sliderEl.addEventListener(EVENTS.slider.mySliderChanged, ((event: CustomEvent) => {
  const detail = event.detail as EVENTS.slider.detailTypes.SliderChangedDetailType;
}) as EventListener)

Вам решать, хотите ли вы изменить уровень вложенности и именования вещей, так как пространство имен делает некоторые вещи избыточными (может быть, вы хотите EVENTS.slider.details.SliderChanged вместо EVENTS.slider.detailTypes.SliderChangedDetailType), но основная идея здесь - общий подход к использованию пространств имен или модулей.

Надеюсь, это поможет; удачи!

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