Kyle
Kyle

Reputation: 130

How to use all property values of an object as a type?

I'm trying to create a class to handle CustomEvents in my app. Here's what it looks like so far:

export const EVENT_NAMES = {
  TEST_EVENT: 'HELLO_WORLD',
  THIS_IS: 'REALLY_HARD'
};

export type EventName = keyof typeof EVENT_NAMES;

export class Events {
  static on(eventName: EventName, eventHandler: Function): void {
    document.addEventListener(eventName, (e: CustomEvent): void => {
      eventHandler(e.detail);
    });
  }
}

/* 
    Want to do this, but TypeScript complains:
    Argument of type 'string' is not assignable to parameter of type 
    '"TEST_EVENT" | "THIS_IS"'. ts(2345)
*/   
Events.on(EVENT_NAMES.TEST_EVENT, () => {
  // handle the event
});

I want to enforce that any value passed to the eventName argument in Events.on is a valid event that belongs in EVENT_NAMES, which is the value of any property in that object, not the key of any prop. I can't quite figure out how to accomplish this, and if anyone has any pointers, that'd be greatly appreciated!

Upvotes: 2

Views: 114

Answers (1)

Wex
Wex

Reputation: 15715

First, your definition of EventName sets you up to use the keys from EVENT_NAMES as your argument, not the values. Second, the type of the values are strings. You can cast those using as:

const EVENT_NAMES = {
  TEST_EVENT: 'HELLO_WORLD',
  THIS_IS: 'REALLY_HARD'
} as const;

// 'HELLO_WORLD' | 'REALLY_HARD'
export type EventName = typeof EVENT_NAMES[keyof typeof EVENT_NAMES];

Now, this should work:

Events.on(EventNames.HELLO_WORLD, () => {});

Upvotes: 1

Related Questions