假设我们正在为 Post
编写数据库模型,并且由于数据库将所有内容存储为字符串,我们需要编写 parse
函数,该函数将获取原始数据库对象并将其转换为正确的 Post
接口(interface)。
重现设置noImplicitReturns: true
interface Post {
id: number
text: string
}
function parse<K extends keyof Post>(k: K, v: any): Post[K] {
switch(k) {
case 'id': return parseInt(v)
case 'text': return v.toString()
}
}
该代码中有两个错误。首先 - 它不会编译,似乎 TypeScript 没有意识到我们的代码是正确的,并要求将 default
语句添加到 switch
中。
第二个错误 - 它不会检测到您正在检查错误的值。下面的错误代码将编译没有错误
function parse<K extends keyof Post>(k: K, v: any): Post[K] {
switch(k) {
case 'id': return parseInt(v)
case 'text': return v.toString()
case 'some': return v.toString() // <= error, no `some` key
default: return '' // <= this line is not needed
}
}
甚至还有第三个错误,TypeScript 会允许返回错误的键值,这个错误的代码会编译
function parse<K extends keyof Post>(k: K, v: any): Post[K] {
switch(k) {
case 'id': return parseInt(v)
case 'text': return 2 // <= error, it should be string, not number
default: return ''
}
}
这些 TypeScript 限制还是我搞错了?
最佳答案
首先,K
扩展keyof Post
并不意味着K
是keyof Post
,所以不要使用泛型类型K
,您必须使用keyof Post
来限制K
的潜在值。
其次,如果您在 tsconfig.json 中设置 "switch-default": true,
,则会强制使用默认选项。因此将其设置为 false
那么问题就会消失。
第三,Post[K]
甚至 Post[keyof Post]
将返回 Post
属性的所有可能类型,因此 number
是可能的。 Typescript 不会强制 Post[K]
为其 K
属性的类型,除非您指出 K
是哪个。否则,您必须定义映射类型,例如 type A = ['id', numer] | [text', string]
并将 Post
定义为 [A[0]]: A[1]
希望这有帮助
关于TypeScript、详尽性检查无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54821093/