我希望你能提供一种通用且类型安全的方法,将以下JavaScript代码转换为TypeScript:
这个工具的想法是将一个数组缩减为一个以给定键值为键的对象,并且其值可以是整个对象或者在给定第二个键处的特定数据点(这个解释可能有些欠佳,但希望示例可以说明问题)。
这是相当简单的JS代码,但在TS中似乎很难得到正确的类型。目前为止,我已经想出了下面的方法,但必须创建两个函数才能得到正确的返回类型,感觉有点笨拙。我无法让条件返回类型在这里起作用,所以如果必须要使用两个函数,那么就OK。但我想知道是否有更好的方法(也许可以将记录键入
const records = [
{ name: "foo", id: 1, data: ["foo"] },
{ name: "bar", id: 2, data: ["bar"] },
{ name: "baz", id: 3, data: ["baz"] }
];
function keyBy(collection, k1, k2) {
if (k2) {
return collection.reduce((acc, curr) =>
({ ...acc, [curr[k1]]: curr[k2] }), {});
} else {
return collection.reduce((acc, curr) =>
({ ...acc, [curr[k1]]: curr }), {});
}
}
console.log(keyBy(records, "name", "data"));
// { foo: [ 'foo' ], bar: [ 'bar' ], baz: [ 'baz' ] }
console.log(keyBy(records, "name"));
// {
// foo: { name: 'foo', id: 1, data: [ 'foo' ] },
// bar: { name: 'bar', id: 2, data: [ 'bar' ] },
// baz: { name: 'baz', id: 3, data: [ 'baz' ] }
// }
这个工具的想法是将一个数组缩减为一个以给定键值为键的对象,并且其值可以是整个对象或者在给定第二个键处的特定数据点(这个解释可能有些欠佳,但希望示例可以说明问题)。
这是相当简单的JS代码,但在TS中似乎很难得到正确的类型。目前为止,我已经想出了下面的方法,但必须创建两个函数才能得到正确的返回类型,感觉有点笨拙。我无法让条件返回类型在这里起作用,所以如果必须要使用两个函数,那么就OK。但我想知道是否有更好的方法(也许可以将记录键入
Record<T[K], T>
或Record<T[K], T[K2]>
而不是记录键入ObjectKey
)。谢谢。type ObjectKey = string | number | symbol;
const isValidKey = (x: any): x is ObjectKey =>
typeof x === "string" || typeof x === "number" || typeof x === "symbol";
function keyBy<T extends object, K extends keyof T>(collection: T[], key: K) {
return collection.reduce((acc, curr) => {
const valueAtKey = curr[key];
if (isValidKey(valueAtKey)) {
return { ...acc, [valueAtKey]: curr };
}
throw new Error("T[K] is not a valid object key type");
}, {} as Record<KeyType, T>);
}
function keyByWith<T extends object, K extends keyof T, K2 extends keyof T>(
collection: T[],
k: K,
k2: K2,
) {
return collection.reduce((acc, curr) => {
const valueAtKey = curr[k];
if (isValidKey(valueAtKey)) {
return { ...acc, [valueAtKey]: curr[k2] };
}
throw new Error("T[K] is not a valid object key type");
}, {} as Record<ObjectKey, T[K2]>);
}
附言:我知道lodash有一个类似的keyBy
函数,但我认为他们没有任何类似于上面展示的keyByWith
。
T[K]&ObjectKey
以将记录的键缩小到T[K]
,这些都是缺失的关键。在我的实际项目中,as const
不一定会有很大的区别,因为我通常会使用最初推断出记录数组的类型作为记录类型,例如type User = { name: string; id: number: data: string[]; }
。因此,能够将其作为Record<string, User>
或Record<string, string[]>
得到是可以接受的,特别是如果我可以合并成一个单独的函数。 - no_stack_dub_sack