[英]Typescript generics is rejected when specifying `keyof?
I have a generic method which is from the RXJS library ( here simplified ) : 我有一个来自RXJS库的通用方法( 这里简化 ):
function Subject<T>(t: T):T {
return t;
}
I also have an interface which declares my app values. 我还有一个声明我的app值的界面。 ( keys can be added )
( 可以添加键 )
interface IState {
key1: number;
key2: string;
}
And finally I have a Store
which applies to the IState
interface with actual values, via the generic function wrapper ( the generic function is an alias to the RXJS
subject ) 最后我有一个
Store
,通过泛型函数包装器将实际值应用于IState
接口( 泛型函数是RXJS
主题的别名 )
let Store : IState= Subject<IState>({
key1: void 0,
key2: void 0,
})
Ok so lets add 2 method for getting & setting from store : 好吧,让我们添加2个方法来从商店获取和设置:
Setting to store : 设置存储:
function set<T>(name: keyof IState, statePart: T) {
Store={
...Store,
[name]: statePart
};
Usage : set<string>("key1", "3");
用法:
set<string>("key1", "3");
This function works fine and allows me to only use valid keys which belongs to IState
. 此函数工作正常,并允许我只使用属于
IState
有效密钥 。 No errors here. 这里没有错误。
But looking at the Select
method : 但是看看
Select
方法:
(invocation should be like: ) (调用应该像:)
let myVal:number = select<number>("key1");
Here is the method : 这是方法:
function select<T>(k: keyof IState): T {
return <T>Store[k]; // <-- error here
}
Type 'string |
输入'string | number' cannot be converted to type 'T'.
number'无法转换为'T'类型。 Type 'number' is not comparable to type 'T'.
类型'number'与'T'类型不可比。
Question: 题:
Why is that ? 这是为什么 ? If I remove the
keyof
: 如果我删除
keyof
:
function select<T>(k): T {
return <T>Store[k];
}
Then it does compile , but it's not making any sense , Store
is type of Istate
and Istate
contains keys of Istate
随后,它编译,但它没有做出任何意义,
Store
的类型为Istate
和Istate
包含的键Istate
Why does it work without keyof
and how can I fix my code so that select
method will force to select only keys of Istate
? 为什么没有
keyof
它可以工作,我如何修复我的代码,以便select
方法将强制只选择Istate
键?
The problem is that k
can be any key of IState
so there is no way to make sure that Store[k]
is compatible with T
. 问题是
k
可以是IState
任何键,因此无法确保Store[k]
与T
兼容。 I would change the generic parameter to be the key, and type the result in relation to the field type: 我会将通用参数更改为键,并键入与字段类型相关的结果:
function select<K extends keyof IState>(k: K): IState[K] {
return Store[k];
}
let myVal = select("key1"); // myval is number
Also set
can be improved to not have explicit generic parameters, and to ensure the value passed to set
is compatible with the field type: 还可以将
set
为不具有显式泛型参数,并确保传递给set
的值与字段类型兼容:
function set<K extends keyof IState>(name: K, statePart: IState[K]) {
Store={
...Store,
[name]: statePart
}
}
set("key1", 3);
Edit 编辑
As mentioned in the comments, you can see the actual inferred types if you hover over the call (at least in vscode): 如评论中所述,如果将鼠标悬停在调用上,则可以看到实际的推断类型(至少在vscode中):
If you want to keep the explicit type parameters, although I do not recommend this as you can easily mismatch the field type and the call type you can use a type assertion through any
: 如果你想保留显式类型参数,虽然我不推荐这个,因为你很容易不匹配字段类型和调用类型,你可以通过
any
使用类型断言:
function select3<T>(k: keyof IState): T {
return Store[k] as any;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.