我有这个:
export function reduceByProp<T, Y extends keyof T>(
array: T[],
mapper: (a: T) => Y
): { [key: Y]: T } {
return array.reduce(
(previous: T, current: T) => ({ ...previous, [mapper(current)]: current }),
{}
);
}
但是TypeScript对[key: Y]
不满意,因为索引是string
或number
。但是由于Y
是T
的键,因此默认情况下也是字符串或数字,对吗?
答案 0 :(得分:1)
我建议您将代码更改为如下形式:
function reduceByProp<T, K extends PropertyKey>(
array: T[],
mapper: (a: T) => K
) {
return array.reduce(
(previous, current) => ({ ...previous, [mapper(current)]: current }),
{} as { [P in K]?: T }
);
}
解释差异:
对于您的问题,您不能执行{[key: K]: T}
之类的操作,因为索引签名被限制为 all 字符串或所有数字。相反,您可以使用{[P in K]: T}
形式的mapped types。
除非您希望reduceByProp([{foo: 1}], v => "bar")
失败,否则应使K extends PropertyKey
而不是K extends keyof T
。 keyof T
仅是数组对象内部的键,而PropertyKey
是您想要的任何键。
不要注释previous
和current
,或者如果要注释它们,则不要将它们注释为T
。 current
绝对是T
,但是previous
是累加器,不是T
,而是reduceByProp()
的返回类型,它的返回值由{{ 1}},其值类型为mapper()
。
给初始的reduce对象T
一个显式类型,否则指定{}
的预期结果。否则将推断值reduce()
为类型{}
,否则将无法输入check。所以我给了它{}
。
我设置了返回类型{} as ...
,其中的属性是可选的({[P in K]?: T}
),而不是?
中的必填属性。原因是您可能想拨打这样的电话:
{[P in K]: T}
在我的版本中,该返回类型为reduceByProp([{ foo: 1 }, { foo: 3 }, { foo: 5 }], v => v.foo % 2 === 0 ? "even" : "odd");
。最好是可选的,因为事实证明输出根本没有{even?: {foo: number}, odd?: {foo: number}}
键。
好的,希望能有所帮助;祝你好运!