类型“未定义”不能分配给类型“从不”

时间:2019-12-04 09:49:04

标签: typescript

interface A {
  name?: string
  age: number
}

var a: A = {
  name: '',
  age: 23
}

var result:A = (Object.keys(a) as Array<keyof A>).reduce((prev, key) => {
  if (a[key] || a[key] === 0) {
    prev[key] = a[key] // this reported a error about `Type 'undefined' is not assignable to type 'never'`
  }
  return prev
}, {} as A)

console.log(JSON.stringify(result))

上面是复制代码。

我发现代码可以在typescript@~3.4.0下运行,但是不能在typescript@^3.5.0下编译,并且我检查了3.4和3.5之间的更新日志,但是我没有找到任何关于此的引用。 / p>

所以我猜是否是因为未设置index signature,然后:

interface A {
  name?: string
  age: number
  [K:string]:any <-- add this line
}

var a: A = {
  name: '',
  age: 23
}

var result:A = (Object.keys(a) as Array<keyof A>).reduce((prev, key/* validation lost */) => {
  if (a[key] || a[key] === 0) {
    prev[key] = a[key]
  }
  return prev
}, {} as A)

console.log(JSON.stringify(result))

先前的错误消失了,但是key回调中作为参数的reduce的类型变为string|number,从而导致密钥的类型验证丢失。

这是正常现象吗?

如果是,我想知道如何解决Type 'undefined' is not assignable to type 'never',并保持key的类型检查。

1 个答案:

答案 0 :(得分:2)

在TS 3.5中,PR Improve soundness of indexed access types实际上发生了重大变化:

  

当索引访问T [K]发生在类型关系的源侧时,它将解析为T [K]选择的属性的并集类型,但是当它发生在类型关系的目标侧时,现在,它解析为T [K]选择的属性的交集类型。以前,目标端也会解析为联合类型,这是不合理的。

继续进行到您的示例,prev[key] = a[key]现在发出错误,因为key具有联合类型"name" | "age",并且prev[key](分配的目标方)解析为所有选定属性的交集类型:A["name"] & A["age"],即string & number或换句话说never({类型prev的{​​{1}})。

A的推断交集背后的想法是确保可以安全地写入prev[key]中所有可能的键"name" | "age"。如果prev的运行时值为key,向其中写入age(预期属性类型为string)将是错误的。在使用类型name进行编译时,我们不知道keyof A的确切值是什么,因此PR中的更改会强制使用更安全的类型。

解决方案是为对象(key)和/或属性名称(prev)引入通用类型参数。维护者提供了一些示例hereherehere。我不确定您的用例,但是例如您可以重写如下代码:

key

Playground