这是我得到的一段代码:
interface Obj {
a: number
b: string
}
const obj: Obj = {
a: 1,
b: 'hi'
}
function fn(key: keyof Obj, value: Obj[keyof Obj]) {
let foo = obj[key]
obj[key] = value
}
fn("a", 2)
所以我想做的是,我希望函数fn()
能够更新对象obj
属性,该函数的第一个参数是obj
具有(在Obj
接口中定义)的任何键,第二个参数是您想要为其提供的值键。
但是,obj[key] = value
此行中出现错误的打字稿弹出窗口是:
Type 'string | number' is not assignable to type 'never'.
Type 'string' is not assignable to type 'never'.(2322)
这是屏幕截图:
如果将鼠标悬停在变量上foo
(图片中的第13行),它会在这里发生奇怪的事情:
let foo: string | number
which means, obj[key]
's type is string | number
, but the error says obj[key]
type is never
.
so my first question is: How come a
string | number
type magically becomes a never type? Is there any way to fix this?
Then i got another piece of code which solves this problem:
interface Obj {
a: number
b: string
}
const obj: Obj = {
a: 1,
b: 'hi'
}
function fn<K extends keyof Obj>(key: K, value: Obj[K]) {
obj[key] = value
}
fn("a", 2)
Therefore my second question would be: why using
Generics
solve the problem and what the hack is the keywordextends
here?
BTW, all the code are tested in typescript 3.7.5
version.
I am not a native English speaker, hope i explained my confusion clearly.
该怎么办,这是因为keyof Obj
可能是"a"
或"b"
具有类型number
或string
。在表达式obj[key]
的编译器不知道的属性类型,它可能number
还是string
一样,所以它不允许这样的分配。这是同样的问题。您可以在此处找到解释,请参阅针对索引访问类型的不正确写入的修复。
在通用功能的情况下,K extends keyof Obj
意味着K
类型可以是"a"
或"b"
为好,但是当你调用函数fn("a", 2)
你隐式设置K
到"a"
,编译器推断K
从第一个参数类型。所以,现在,里面的呼叫内容key
有"a"
型且Obj[K]
为number
,因此分配变得正确。
我只是想向我的妻子(不是程序员)解释这种区别:)我认为这可能也有帮助:
通常的功能:假设您正在吃蛋糕,但闭着眼睛。您知道这可能是樱桃蛋糕或香蕉蛋糕。您喜欢味道,但不能说“多么美味的香蕉蛋糕!” 因为您不确定这是香蕉蛋糕。
通用功能:在这种情况下,您可以睁开眼睛,可以选择要吃的蛋糕,但仍然有两种选择:樱桃或香蕉。现在,如果您选择并品尝了香蕉蛋糕,则可以说“多么美味的香蕉蛋糕!”。
谢谢您的解释,但是正如您所说的,我只是遇到一个愚蠢的问题:“您将K隐式设置为a”,但是为什么不能
keyof Obj
这样做呢?为什么也不能隐式设置keyof Obj
为“ a”?幕后到底发生了什么?@Limboer泛型允许您在调用函数时指定类型。就像
keyof Obj
您的情况一样,通常的函数参数类型是常量。对于泛型函数,您告诉编译器该函数接受一个类型的参数K
并且该类型应该满足约束extends keyof Obj
,换句话说,它必须是"a"
或"b"
。调用函数时,您fn<"a">("a", 2)
可以明确指定喜欢的类型,也可以从传递给函数的参数中隐式地推断出类型,但现在它不是联合类型,"a" | "b"
而只是"a"
。希望对您有帮助@Limboer我也为答案添加了真实的解释,我希望它也可能有所帮助