是否有方法从对象数组中推断名称值,并让新对象使用这些值作为输出类型的键?
interface TypeA {
name: string;
value: number;
}
interface TypeB {
[key: string]: { value: any };
}
// can this be created without hard-coding a new type containing the values?
interface OutputType {
test: {value: any},
test2: {value: any},
}
const arrayOfObjectsToObject = (array: TypeA[]):OutputType =>
array.reduce((acc: TypeB, { name, value }: TypeA) => {
acc[name] = { value };
return acc;
}, {});
const result = arrayOfObjectsToObject([ // {test:{value:1}, test2:{value:2}} etc...
{ name: 'test', value: 1 },
{ name: 'test2', value: 2 }
]);发布于 2022-08-30 22:11:06
我们可以定义一个泛型类型ToOutputType,它接受一个元组,并使用映射类型将该类型转换为所需的对象类型。
type ToOutputType<T extends { name: string, value: any }[]> = {
[K in T[number] as K["name"]]: { value: K["value"] }
} 我们还修改了arrayOfObjectsToObject,使其成为通用的。
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
const arrayOfObjectsToObject =
<
T extends { name: K, value: any }[],
K extends string
>(array: readonly [...T]): Expand<ToOutputType<T>> => {
return array.reduce((acc, { name, value }) => {
acc[name] = { value };
return acc;
}, {} as any) as Expand<ToOutputType<T>>;
}T将保存传递给函数的元组。K将用于将元组中的字符串缩小到文字类型。我们使用类型Expand<ToOutputType<T>>作为返回类型。使用Expand类型只是为了使类型更漂亮。
调用该函数时,将得到以下结果。
const result = arrayOfObjectsToObject([
{ name: 'test', value: 1 },
{ name: 'test2', value: 2 }
]);
const a = result.test
// ^? { value: number; }
const b = result.test2
// ^? { value: number; }注意,在这两种情况下,value的类型都是number。TypeScript自动将数字扩展到number。为了防止这种情况,我们可以使用as const。
const result = arrayOfObjectsToObject([
{ name: 'test', value: 1 },
{ name: 'test2', value: 2 }
] as const);
const a = result.test
// ^? { value: 1; }
const b = result.test2
// ^? { value: 2; }如果您不想使用as const,我们也可以使用一种特殊的通用类型进行推理。
type Narrowable = string | number | boolean | symbol | object | undefined | void | null | {};
const arrayOfObjectsToObject =
<
T extends { name: K, value: N }[],
N extends { [k: string]: N | T | [] } | Narrowable,
K extends string
>(array: readonly [...T]): Expand<ToOutputType<T>> => {
return array.reduce((acc, { name, value }) => {
acc[name] = { value };
return acc;
}, {} as any) as Expand<ToOutputType<T>>;
}https://stackoverflow.com/questions/73548743
复制相似问题