【问题标题】:Why can't I write to object property with index type inference为什么我不能使用索引类型推断写入对象属性
【发布时间】:2020-07-04 23:20:28
【问题描述】:

我有这个功能

function foo<T extends { [P in K]: number }, K extends keyof T>(obj: T, key: K): void {
  const x: number = obj[key]
  obj[key] = 123 //error
}

obj[key] 的类型为 number 但我不能给它写数字

类型“123”不可分配给类型“T[K]”。

如何解决?

【问题讨论】:

    标签: typescript typescript-generics mapped-types


    【解决方案1】:

    这是按预期工作的。假设你像这样调用foo

    const obj = {a: 42} as const
    foo(obj,"a") 
    // foo<{readonly a: 42; }, "a">(obj: { readonly a: 42; }, key: "a"): void
    

    那么T[K] 将不是number,而是42(一个子类型) - 将123 分配给a 将不再有效。在foo 正文中,我们只能确定T[K] 是某种numberT 的通用约束),但不是 exact 类型。

    因此 TS 将发出错误 Type '123' is not assignable to type 'T[K]' - 编译器无法确保 123 是正确的类型,因为泛型类型由 foo调用者 设置。唯一可以静态检查的类型是T[K]

    要将number写入某些属性K,您可以按如下方式更改签名:

    function foo<K extends PropertyKey>(obj: Record<K, number>, key: K): void {
      const x: number = obj[key]
      obj[key] = 123 
    }
    
    const obj = { foo: 1, bar: true }
    foo(obj, 'foo') // works
    

    TS Playground sample

    【讨论】:

    • 我想将此函数与任何对象 foo({foo: 1, bar: boolean}, 'foo') 一起使用,因此所有属性的编号对我不起作用
    • 有两种可能:如果你想用对象字面量参数直接调用foo,没有理由指定除number属性之外的任何东西,因为foo只能处理numbers。另一种情况是一些存在的对象,您只需将其传递给foo。后者已经可以工作了,因为编译器在这里没有进行过多的属性检查——看看更新的答案。
    猜你喜欢
    • 2017-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多