我有一个来自RXJS库的通用方法(这里简化):
function Subject<T>(t: T):T {
return t;
}
我还有一个声明我的app值的界面。 (键可以添加)
interface IState {
key1: number;
key2: string;
}
最后我有Store
通过泛型函数包装器将IState
接口应用于实际值(泛型函数是RXJS
主题的别名)
let Store : IState= Subject<IState>({
key1: void 0,
key2: void 0,
})
好的,让我们添加2个方法来获取&amp;从商店设置:
设置存储:
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
}
输入'string | number'无法转换为'T'类型。类型 'number'与'T'类型不可比。
问题:
为什么?如果我删除keyof
:
function select<T>(k): T {
return <T>Store[k];
}
然后它确实编译,但它没有任何意义,Store
是Istate
的类型,而Istate
包含Istate
的键
为什么没有keyof
它可以正常工作?如何修复我的代码,以便select
方法强制只选择Istate
的键?
答案 0 :(得分:3)
问题是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中):
如果你想保留显式类型参数,虽然我不推荐这个,因为你很容易不匹配字段类型和调用类型,你可以通过any
使用类型断言:
function select3<T>(k: keyof IState): T {
return Store[k] as any;
}