Reputation: 53
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
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);
Upvotes: 3