假设我有以下内容:
type Field = {
_id: string;
value: string;
}
const fields = [
{ _id: 'a', value: '2' },
{ _id: 'b', value: '3' }
] as const;
我想定义一个产生以下内容的type ValueById<T extends readonly [...Field[]]>
:
{
a: '2',
b: '3',
}
我已经部分地达到了这个目标:
export type ValueById<T extends readonly [...Field[]]> = {
[Z in T[number]['_id']]: T[number]['value']
}
type NewType = ValueById<typeof fields>
但是不幸的是,这产生了以下类型:
{
a: '2' | '3'
b: '2' | '3'
}
有没有办法缩小这里的值的类型?
答案 0 :(得分:1)
首先,我们需要提取array item type:
const fields = [
{ _id: 'a', value: '2' },
{ _id: 'b', value: '3' }
] as const;
type Field = typeof fields[number];
// {
// readonly _id: "a";
// readonly value: "2";
// } | {
// readonly _id: "b";
// readonly value: "3";
// }
现在我们可以使用distributive conditional types
创建“ id-value”对的并集type IdValueUnion<T> = T extends Field ? { [Z in T['_id']]: T['value'] } : never;
// IdValueUnion<Field>
//
// {
// a: "2";
// } | {
// b: "3";
// }
我们非常接近,但我们需要intersection instead of union:
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
// UnionToIntersection<IdValueUnion<Field>>
// {
// a: "2";
// } & {
// b: "3";
// }
最后一步是通过将键重新映射为值来“压缩”交集:
export type Compact<T> = { [K in keyof T]: T[K] };
export type ValueById = Compact<UnionToIntersection<IdValueUnion<Field>>>;
// ?
// {
// a: "2";
// b: "3";
// }
let foo: ValueById = { a: '2', b: '3' }