user2794841
user2794841

Reputation: 53

TypeScript Property does not exist on type typeof enum, after checking that it definitely exists

In the example below, a character can perform several actions, however, we only have verbs for some of the actions.

We check to see that if verb is present before returning it.

TypeScript won't accept that the verb exists, even after we have checked for it in the Enum.

type Action =
| 'WALK'
| 'RUN'
| 'SLEEP'
| 'SWIM';

enum Verbs {
  'WALK' = 'walking',
  'RUN' = 'running',
  'SWIM' = 'swimming',
}

const getVerb = (character: string, action: Action): string => {
  if (action in Verbs) {
    // Property 'SLEEP' does not exist on type 'typeof Verbs'.ts(7053) ─┐
    const  verb = Verbs[action]; // <───────────────────────────────────┘
    return `${character} is ${verb}`;
  }
  return `${character} is doing something weird`;
}

Example codesandbox: https://codesandbox.io/s/nostalgic-grass-7vrpt?file=/src/index.ts

I've worked around it by creating a Partial Record keyed with Action, but it would be good to understand why it won't work with an Enum

const verbs: Partial<Record<Action, string>> = {
  'WALK': 'walking',
  'RUN': 'running',
  'SWIM': 'swimming',
};
const getVerb = (character: string, action: Action): string => {
  if (action in verbs) {
    return `${character} is ${verbs[action]}`; // Works 👍
  }
  return `${character} is doing something weird`;
};

Upvotes: 5

Views: 6550

Answers (1)

blaumeise20
blaumeise20

Reputation: 2220

You have to use type predicates. It looks like this:

type Action =
| 'WALK'
| 'RUN'
| 'SLEEP'
| 'SWIM';

enum Verbs {
  'WALK' = 'walking',
  'RUN' = 'running',
  'SWIM' = 'swimming',
}

const getVerb = (character: string, action: Action): string => {
  if (isVerb(action)) {
    const  verb = Verbs[action];
    return `${character} is ${verb}`;
  }
  return `${character} is doing something weird`;
}

// predicate here
const isVerb = (action: Action): action is keyof typeof Verbs => {
  return action in Verbs; 
}

const character = 'Gom';
const action: Action = 'RUN';
const message = getVerb(character, action);
console.log(message);

TypeScript playground

Upvotes: 3

Related Questions