I have a type Command that encapsulates a set of actions which I discriminate using a property called action
like for example:
type Command =
{ action: "run", x: number, y: number } |
{ action: "jump", height: number } |
{ action: "attack", weapon: "sword" | "knife"}; //... more actions
As you can see, all commands have action but the rest of the properties are different. When I receive the command, type narrowing works as expected to difference between them. The problem is, if I receive a command from the user, how can I validate if its a valid action? something like (pseudocode)
let userCommand: string; // unknown string coming from the user
if (!userCommand in Command.action){ // something like this
throw `Command "${userCommand}" is unknown`;
}
I know types don't exist at runtime so I don't know if there is a way to check other than manually validating the string against all possible actions duplicating them in the type declaration and in the validation. I found this SO post which covers the same problem when you have a literal union type of strings, but in my case this does not work as the string is part of a bigger type. I don't know if there is a way to validate this, or maybe a better way to design my types so that I can validate this at runtime.
We can use a enum
to define the valid values of action.
enum CommandAction {
RUN = "run",
JUMP = "jump",
ATTACK = "attack",
}
type Command =
{ action: CommandAction.RUN, x: number, y: number } |
{ action: CommandAction.JUMP, height: number } |
{ action: CommandAction.ATTACK, weapon: "sword" | "knife" }; //... more actions
let userCommand: keyof typeof CommandAction = 'RUN'; // unknown string coming from the user
if (!CommandAction[userCommand]) { // something like this
throw `Command "${userCommand}" is unknown`;
}