Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

TypeScript: Idiomatic way to do a switch-case on Enum to set a variable

Example problem: I have an Enum variable Difficulty. In a function, I want to set the config DifficultyConfig depending on the value of Difficulty. Here’s an inelegant way that I can think of:

export interface DifficultyConfig {
    healthModifier: number,
    deathIsPermanent: boolean,
}

export interface AppProps {
    difficultyConfig: DifficultyConfig
}

export const NormalDifficultyConfig: DifficultyConfig = {
    enemyHealthModifier: 1,
    deathIsPermanent: false,
}

export const HigherDifficultyConfig: DifficultyConfig = {
    enemyHealthModifier: 1.3,
    deathIsPermanent: true, 
}

export enum Difficulty {
    NORMAL = 'Normal',
    HARD = 'Hard',
    ADVANCED = 'Advanced',
}

function createApp(difficulty: Difficulty) {
    let difficultyConfig: DifficultyConfig;
    
    switch(difficulty) {
        case Difficulty.NORMAL: 
            difficultyConfig = NormalDifficultyConfig;
            break;
        // Both HARD and ADVANCED get HigherDifficultyConfig
        case Difficulty.HARD:
            difficultyConfig = HigherDifficultyConfig;
            break;
        case Difficulty.ADVANCED: 
            difficultyConfig = HigherDifficultyConfig;
            break;
        default: 
            difficultyConfig = NormalDifficultyConfig;
            break;
    }
    
    return new App({
        difficultyConfig
    });
}

I’m not fond of the Switch case syntax for something so simple. My ideal would be something like this in Scala:

val difficultyConfig = difficulty match {
    case Difficulty.NORMAL => NormalDifficultyConfig
    case Difficulty.HARD | Difficulty.ADVANCED => HigherDifficultyConfig
    case _ => NormalDifficultyConfig
}

Is there an equivalent for this in JavaScript?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

If there’s a difference in logic, a switch or an if/else if/else (slightly less verbose) is probably the way to go (more on this below though). If it’s purely data as in your example, then you could use a difficulty-to-config mapping object:

const difficultyConfigs = {
    [Difficulty.NORMAL]: NormalDifficultyConfig,
    [Difficulty.HARD]: HigherDifficultyConfig,
    [Difficulty.ADVANCED]: HigherDifficultyConfig,
} as const;

You might even declare that as Record<Difficult, DifficultyConfig> like this, as caTS points out in the comments:

const difficultyConfigs: Record<Difficult, DifficultyConfig> = {
//                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    [Difficulty.NORMAL]: NormalDifficultyConfig,
    [Difficulty.HARD]: HigherDifficultyConfig,
    [Difficulty.ADVANCED]: HigherDifficultyConfig,
} as const;

More on that in a minute, but either way, then the function is just:

function createApp(difficulty: Difficulty) {
    let difficultyConfig = difficultyConfigs[difficulty];
    
    return new App({
        difficultyConfig
    });
}

Playground links: Without Record | With Record (I also updated a couple of seeming typos/editing errors in the question’s code.)

This also has the advantage that if you add a Difficulty but forget to include one in difficultyConfigs, you get a handy compile-time error when you use it. I’ve simulated such an error here by adding a MEDIUM difficulty but "forgetting" to update the function.

But better yet, if we include the type Record<Difficulty, DifficultyConfig> type as caTS suggested and difficultyConfigs doesn’t have an entry for every Difficulty value, you get an even earlier compile-time error, like this.


Even for logic, if you like you can use the same sort of concept to create a dispatch object:

const difficultyConfigs = {
    [Difficulty.NORMAL]: () => { /*...build and return NORMAL config...*/ },
    [Difficulty.HARD]: () => { /*...build and return HARD config...*/ },,
    [Difficulty.ADVANCED]: () => { /*...build and return ADVANCED config...*/ },,
} as const;
// ...
const difficultyConfig = difficultyConfigs[difficulty]();
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading