If there is a difference in reasoning, opt for a switch
or an if
/else if
/else
(a bit less wordy) method (more details on this below). If it pertains strictly to data like in your instance, then you could utilize a complexity-to-configuration mapping object:
const difficultyConfigs = {
[Difficulty.NORMAL]: NormalDifficultyConfig,
[Difficulty.HARD]: HigherDifficultyConfig,
[Difficulty.ADVANCED]: HigherDifficultyConfig,
} as const;
You could even define that as
Record<Difficult, DifficultyConfig>
just like this, as highlighted by caTS in the comments:
const difficultyConfigs: Record<Difficult, DifficultyConfig> = {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[Difficulty.NORMAL]: NormalDifficultyConfig,
[Difficulty.HARD]: HigherDifficultyConfig,
[Difficulty.ADVANCED]: HigherDifficultyConfig,
} as const;
More information on that shortly, but either way, the function becomes quite simple:
function createApp(difficulty: Difficulty) {
let difficultyConfig = difficultyConfigs[difficulty];
return new App({
difficultyConfig
});
}
Playground links: Without Record
| With Record
(I also corrected some possible typos/editing mistakes in the original code.)
This approach has the added benefit that if you introduce a new Difficulty
but overlook including it in difficultyConfigs
, you will receive a useful compile-time error when attempting to use it. I have simulated such an error here by adding a MEDIUM
difficulty but failing to update the function.
Even for logic, you can apply the same idea to construct a dispatch object:
const difficultyConfigs: Record<Difficulty, () => DifficultyConfig> = {
[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]();