【发布时间】:2021-02-07 05:15:35
【问题描述】:
我无法理解为什么下面的代码会这样运行:
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'>
我一定是遗漏了一些东西,因为MapOverString 和IfStringMapOverIt 似乎它们的功能应该相同。
最终,我使用字符串文字和泛型通过配置类型的排列进行级联。例如,如果您希望 StringConfig<T> 配置有选项 '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
有人可以启发我吗?这是怎么回事?
【问题讨论】:
-
这真的很有趣。标题的答案似乎是(来自您的代码):是的,他们确实如此。有两种选择实际上很酷。请注意联合中是否包含非字符串 (
"a" | 42 | "b") 的区别。不过,我不知道 为什么 或规则是什么。 :-) -
它背后的逻辑似乎很合乎逻辑,就像如果你有一个类型
type SeparateStrings<T> = T extends string ? T : never并且你像SeparateStrings<'a' | 42 | 'b'>一样使用它并期望你得到'a' | 'b',它的作用是合乎逻辑的:它迭代联合类型,而不是将此联合作为单一类型使用。所以这样的行为似乎是合理的,但不知道如何让它做你想做的事,这真的很有趣:p
标签: typescript typescript-generics mapped-types