I am having no luck understanding why the code below functions as it does:
type MapOverString<T extends string> = { [K in T]: K };
type IfStringMapOverIt<T> = T extends string ? MapOverString<T> : never;
type ThisWorks = MapOverString<'a'>;
// { a: 'a' }
type ThisAlsoWorks = IfStringMapOverIt<'a'>;
// { a: 'a' }
type Union = 'a' | 'b' | 'c';
type ThisWorksToo = MapOverString<Union>;
// { a: 'a', b: 'b', c: 'c' }
type ThisDoesnt = IfStringMapOverIt<Union>;
// MapOverString<'a'> | MapOverString<'b'> | MapOverString<'c'>
I must be missing something, because MapOverString and IfStringMapOverIt seem like they should function identically.
Ultimately, I am using string literals and generics to cascade through permutations of configuration types. For example, if you want StringConfig<T> configured with options 'a' | 'b' | 'c':
type ConfigMap<T> = T extends number
? NumberConfig
: T extends string
? StringConfig<T>
: never
type MyConfig = ConfigMap<'a' | 'b' | 'c'> // so many sad faces
Could someone enlighten me? What's going on here?
"a" | 42 | "b"). I have no idea why or what the rules are, though. :-)type SeparateStrings<T> = T extends string ? T : neverand you use it likeSeparateStrings<'a' | 42 | 'b'>and expect yo get'a' | 'b', it's logical what it does: it iterates over union types instead of working with this union as a single type. So such behaviour seems reasonable, no idea though, how to make it do what you want it to do, that's really interesting :p