我有一个来自 RXJS 库的通用方法(此处简化):
function Subject<T>(t: T):T {
return t;
}
我还有一个声明我的应用程序值的接口(interface)。 (可以添加 key )
interface IState {
key1: number;
key2: string;
}
最后我有一个 Store
适用于 IState
与实际值的接口(interface),通过通用函数包装器(通用函数是 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
的有效 key 。这里没有错误。
但是看着 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
的键?
最佳答案
问题是 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;
}
关于javascript - 指定 `keyof? 时拒绝 Typescript 泛型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49572992/