如何实现这个:
type ActionNames = 'init' | 'reset';
type UnionToObj<U> = {/* TODO HERE */}
type Result = UnionToObj<ActionNames>;
// expect type Result to be `{ init: any, reset: any }`
我已经写了一个实现,但是它不能正常工作,它遇到联合扩展协方差问题:
type UnionToObj<U> = U extends string ? { [K in U]: any } : never;
type Result = UnionToObj<'init' | 'reset'>;
// expecting the type Result to be `{ init: any, reset: any }`
// but i got a union object: `{ init: any } | { reset: any }`
// how do i resolve it ?
主要问题:
- 字符串联合类型到对象类型
- union的协方差在extends子句中
这是一个简单的映射类型:
type UnionToObj<U extends PropertyKey> = { [K in U]: any }
type Result = UnionToObj<ActionNames>;
/* type Result = {
init: any;
reset: any;
} */
这里我们将U
约束为类键,而不是通过条件类型检查它。如果你真的想这样做,你可以用这样的解决方案:
type UnionToObj<U> = [U] extends [PropertyKey] ? { [K in U]: any } : never;
这个和你的版本的区别在于你的版本无意中是一个分布条件类型。由于您不希望联合输入变成联合输出,因此您需要防止条件类型分布,方法是不让U extends ...
直接在已检查的位置带有裸类型参数。将被检查的类型包装在一元组([U] extends ...
)中足以关闭联合分布。
Playground链接到代码