Typescript: How to convert a string to a type

13,739

You can't really convert strings to types without a mapping. In fact, you really don't want those strings in the first place except for the actual string passed into addEventListener() as the type parameter. It seems like what you actually want is something like namespaces or modules to organize your types.

For example, using namespaces we can get something similar to your EVENTS object, except that instead of referring to just string values, it refers to string values and types:

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

This should give you the same autocompletes you saw before, plus ones for the types:

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)

It's up to you if you want to change the level of nesting and naming of things since the namespace makes some things redundant (maybe you want EVENTS.slider.details.SliderChanged instead of EVENTS.slider.detailTypes.SliderChangedDetailType), but the main idea here is the general approach of using namespaces or modules.

Hope that helps; good luck!

Share:
13,739
Marek Krzeminski
Author by

Marek Krzeminski

3D OpenGL, C++, HTML, TypeScript, & Game Developer

Updated on October 10, 2022

Comments

  • Marek Krzeminski
    Marek Krzeminski over 1 year

    I am creating a bunch of web components and each of them can emit custom events. As an example here are two simple examples:

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

    To listen to the components I have code that looks like:

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

    As I'm making more components, I'm having difficulty remembering all the custom event names that each component can emit, or the detailType that each event generates.

    To solve this problem I was hoping to create an object that contains all the information like this:

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

    With that, I now have an easy way to access all the Event names available for each component with auto-complete helping me along the way as I type:

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

    The problem that I am having is I don't know how to convert a string to a type. I'd like to be able to type this:

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

    Is there a way to convert strings to types in TypeScript?

  • Marek Krzeminski
    Marek Krzeminski over 5 years
    fantastic, this is exactly what I was looking for!