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
的类型检查。
答案 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
)引入通用类型参数。维护者提供了一些示例here,here和here。我不确定您的用例,但是例如您可以重写如下代码:
key