When designing a library, I wanted to implement the feature of allowing users to modify its configuration using presets. My approach was to define an Enum containing all possible presets and exporting it with the select function.
Unfortunately, my initial plan did not work out as expected due to some unexpected behavior from the type checker.
The code snippet below showcases the presets and the select method implementation. However, there is an issue where an "illegal" preset is required. Removing this illegal preset (a.1) causes the type checker to complain about Presets lacking an index property. Keeping the illegal preset in the enum requires adding a property to the Presets const with the enum value as the key.
Another complication arises when trying to use the enum for creating the Presets const itself. Uncommenting (b.2) results in everything functioning correctly. However, commenting out (b.1) leads to the type checker flagging an incompatibility error (b.3).
What am I missing here?
export enum Preset
{
EASY = 'one',
DEFAULT = 'two',
HARD = 'three',
IMPOSSIBLE = 'do_not_use' // (a.1)
}
type Config = Record<'a' | 'b', number>
type PresetNames = Preset.DEFAULT | Preset.EASY | Preset.HARD
type ConfigByPreset = Record<PresetNames, Config>
/* (b.3)
* [ts] Type '{ [x: string]: { a: number; b: number; }; one: { a: number; b: number; }; two: { a: number; b: nu...'
* is not assignable to type 'Record<PresetNames, Record<"a" | "b", number>>'.
* Property 'three' is missing in type '{ [x: string]: { a: number; b: number; }; one: { a: number; b: number; };
* two: { a: number; b: nu...'.
*/
const Presets: ConfigByPreset = {
one: { a: 1, b: 101 },
two: { a: 2, b: 201 },
['three']: { a: 3, b: 301 }, // (b.1)
// [Preset.HARD]: { a: 4, b: 301 }, // (b.2)
}
const defaultConfig = Presets[Preset.DEFAULT]
export function selectPreset( preset: PresetNames )
{
// (a.2) [ts] Element implicitly has an 'any' type because type 'Record<Preset, Record<"a" | "b", number>>' has no index signature.
const selectedConfig = Presets[preset]
const otherConfig = Presets['three']
console.log( 'config = ', selectedConfig, otherConfig, defaultConfig )
}
selectPreset( Preset.EASY )