指定`keyof?

时间:2018-03-30 10:47:12

标签: javascript typescript

我有一个来自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];
}

然后它确实编译,但它没有任何意义,StoreIstate的类型,而Istate包含Istate的键

为什么没有keyof它可以正常工作?如何修复我的代码,以便select方法强制只选择Istate的键?

ONLINE DEMO

1 个答案:

答案 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中):

enter image description here

如果你想保留显式类型参数,虽然我不推荐这个,因为你很容易不匹配字段类型和调用类型,你可以通过any使用类型断言:

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