为啥打字稿不能用 <T extends Person, K extends keyof T> generic 正确推断 T[K]?

Posted

技术标签:

【中文标题】为啥打字稿不能用 <T extends Person, K extends keyof T> generic 正确推断 T[K]?【英文标题】:Why typescript does not properly infer T[K] with <T extends Person, K extends keyof T> generic?为什么打字稿不能用 <T extends Person, K extends keyof T> generic 正确推断 T[K]? 【发布时间】:2022-01-21 04:34:19 【问题描述】:

我创建了一个 React 钩子:

interface Person 
    name: string
    age: number


export const usePerson = function <T extends Person, K extends keyof T>(): (property: K, setter: (value: T[K]) => T[K]) => void 

    const setPersonProperty = (property: K, setter: (value: T[K]) => T[K]): void => 
        console.log(property, setter)
    

    setPersonProperty('name', (x) => x)

    return setPersonProperty;

我从 typescript 文档中看到了模式 &lt;T, K extends keyof T&gt;,但我无法在我的示例中正确使用它。

更具体地说,打字稿抱怨就行了

setPersonProperty('name', (x) => x)

虽然当我开始输入 setPersonProperty('n /* IDE autocompletes name */ 但抱怨 'name' 参数时,我收到以下错误:

Argument of type 'string' is not assignable to parameter of type 'K'.   'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string | number | symbol'.

我还发布了我的 IDE 中的图像。我正在使用打字稿 4+。 [![在此处输入图片描述][1]][1]

我在这里做错了什么? [1]:https://i.stack.imgur.com/WzJE5.png

【问题讨论】:

【参考方案1】:

我敢打赌,这就是你想要达到的结果

type Person = 
    name: string,
    age: number
;

export const usePerson = function <T extends Person>() 
    const setPersonProperty = <K extends keyof T> (property: K, setter: (value: T[K]) => T[K]): void => 
        console.log(property, setter)
    

    setPersonProperty("name", (x) => x)

    return setPersonProperty;


 const setPerson = usePerson<Person>()

 setPerson("name", (name) => name)

基本上,在您提供的代码中,当调用此 usePerson 挂钩 TK (&lt;T extends Person, K extends keyof T&gt;) 时,有两种通用类型。

假设有人会用usePerson&lt;Person, "age"&gt;() 调用这个函数。 打字稿会做什么它将替换我们usePerson中的类型为T = PersonK = "age"

现在你有一个不匹配,因为setPersonProperty 有第一个类型为 K(“年龄”)的参数,参数“名称”是不可分配的 - 你看到的错误。

【讨论】:

以上是关于为啥打字稿不能用 <T extends Person, K extends keyof T> generic 正确推断 T[K]?的主要内容,如果未能解决你的问题,请参考以下文章

为啥打字稿允许我覆盖一个空的状态对象?

为啥打字稿抱怨对象必须是扩展类型中的对象

打字稿:使用特定的扩展接口来满足通用的“扩展”类型参数?

具有通用返回类型的打字稿函数

打字稿中可调用类型关系的问题

为啥打字稿不显示错误? (反应)