微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

指定`keyof?时,Typescript泛型被拒绝.

我有一个通用方法,该方法来自RXJS库(此处简化):

function Subject<T>(t: T):T {
    return t;
}

我还有一个接口声明我的应用程序值. (可以添加键)

interface IState { 
    key1: number;
    key2: string;
}

最后,我有一个Store,它通过通用函数包装器将IState接口应用于具有实际值的IState接口(通用函数是RXJS主题的​​别名)

let Store  : IState=  Subject<IState>({  
    key1: void 0,
    key2: void 0,

})

好的,让我们添加2种获取&从商店设置:

设置存储:

 function set<T>(name: keyof IState, statePart: T) {
        Store={
            ...Store,
            [name]: statePart 
        };

用法:set< string>(“ key1”,“ 3”);

函数工作正常,只允许我使用属于IState的有效密钥.这里没有错误.

但是看一下Select方法

(调用应类似于:)

let myVal:number = select<number>("key1");

这是方法

function select<T>(k: keyof IState): T { 
    return <T>Store[k];  // <-- error here
}

Type ‘string | number’ cannot be converted to type ‘T’. Type
‘number’ is not comparable to type ‘T’.

题:

这是为什么 ?如果我删除keyof:

function select<T>(k): T { 
    return <T>Store[k];
}

然后它会进行编译,但没有任何意义,Store是Istate的类型,并且Istate包含Istate的键

为什么在没有keyof的情况下它可以工作,如何修复我的代码,以便select方法将强制仅选择Istate的键?

ONLINE DEMO

解决方法:

问题在于k可以是IState的任何键,因此无法确保Store [k]与T兼容.我将泛型参数更改为键,并根据字段类型键入结果:

function select<K extends keyof IState>(k: K): IState[K] { 
    return Store[k];
}
let myVal  = select("key1"); // myval is number

还可以改进set使其不具有显式的泛型参数,并确保传递给set的值与字段类型兼容:

function set<K extends keyof IState>(name: K, statePart: IState[K]) {
    Store={
        ...Store,
        [name]: statePart 
    }
}

set("key1", 3);

编辑

如注释中所述,如果将鼠标悬停在调用上(至少在vscode中),则可以看到实际的推断类型:

enter image description here

如果您要保留显式类型参数,尽管我不建议您这样做,因为您很容易使字段类型和调用类型不匹配,您可以通过以下任何一种使用类型断言:

function select3<T>(k: keyof IState): T { 
    return Store[k] as any;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐