【问题标题】:why is extends keys T not a valid index为什么扩展键 T 不是有效索引
【发布时间】:2020-05-21 17:16:09
【问题描述】:

我有这个:

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] 不满意,因为索引是 stringnumber。但是由于YT 的键,所以默认情况下它也是字符串或数字,对吗?

【问题讨论】:

  • 您能否展示您尝试通过reduceByProp 实现的通话示例?
  • 不确定这是否是这里的原因,但这个文档说keyof 产生string | number | symbol,所以符号可能会搞砸。 typescriptlang.org/docs/handbook/release-notes/…
  • 我很容易告诉您将{[key: Y]: T} 更改为{[K in Y]: T},但我不确定您的其余代码,因为这些类型对我来说似乎不合适。我会将其更改为 this 除非您有理由,例如,您希望将 Y 限制为 keyof T 而不仅仅是任何键。
  • @jcalz - 现在可以了。 :-) 或者当然是第二个。

标签: typescript


【解决方案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 =&gt; "bar") 失败,否则您应该创建 K extends PropertyKey 而不是 K extends keyof Tkeyof T 只是数组中对象内的键,而PropertyKey 是您想要的任何键。

  • 不要注释previouscurrent,或者如果你注释它们,不要将它们注释为Tcurrent 肯定是T,但previous 是一个累加器,不是T,而是reduceByProp() 的返回类型,它的键由mapper() 返回,其值类型是T

  • 给初始 reduce 对象 {} 一个显式类型,或者指定 reduce() 预期产生的内容。 {} 的值将被推断为{} 类型,否则将无法进行类型检查。所以我给了它{} 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}}。最好这些是可选的,因为事实证明输出根本没有 even 键。

好的,希望对您有所帮助;祝你好运!

Playground link to code

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-06
    • 1970-01-01
    • 2020-04-13
    • 2020-06-17
    • 2011-04-29
    • 2011-05-26
    • 1970-01-01
    相关资源
    最近更新 更多