如何为" string"编写用户定义的类型保护| "文字" | "类型&#34 ;?

时间:2017-02-01 16:25:54

标签: typescript

我有以下功能:

change(key: keyof McuParams, dispatch: Function) {
  /** Body removed for brevity */
}

当我调用该函数时......

this.change(VARIABLE_FROM_MY_API, this.props.dispatch)

...我(可以理解)得到以下错误:

Argument of type 'string' is not assignable to parameter of type '"foo" | "bar"'

这是有道理的,因为编译器无法知道我的API在编译时发送了什么。但是,user defined type guards有时可用于在运行时推断类型信息,并通过条件将该信息传递给编译器。

keyof仅被定义为类型(而不是数组)时,是否可以为keyOf foo字符串类型(例如foo)编写用户定义的类型保护)?如果是这样,怎么样?

3 个答案:

答案 0 :(得分:2)

以下是一个例子:

interface McuParams {
    foo, bar, baz;
}

function change(key: keyof McuParams, dispatch: Function) {
}

function isKeyOfMcuParams(x: string): x is keyof McuParams {
    switch (x) {
        case 'foo':
        case 'bar':
        case 'baz':
            return true;
        default:
            return false;
    }
}

function doSomething() {
    const VAR_FROM_API = <string>'qua';
    if (!isKeyOfMcuParams(VAR_FROM_API)) return;
    change(VAR_FROM_API, () => { });
}

doSomething中,您可以使用您喜欢的任何控制流程块,而不是return(例如ifthrow等)。

答案 1 :(得分:1)

尝试以下方法:

 enum mcuParams { foo, bar };
 type McuParams = keyof typeof mcuParams;    

 function isMcuParams(value: string) : value is McuParams {        
     return mcuParams.hasOwnProperty(value);        
 }

 function change(key: McuParams) {
     //do something
 }

 let someString = 'something';

if (isMcuParams(someString)) {
    change(someString);
 }

更新:

我上面写的例子假设我们已经知道McuParams('foo'或'bar')的可能值。以下示例不做任何假设。我测试了它,它按预期工作。每次运行代码时,都会根据随机生成的值得到不同的响应。

function getAllowedKeys() {
    //get keys from somewhere. here, I generated 2 random strings just for the sake of simplicity
    let randomString1 = String(Math.round(Math.random())); //0 or 1
    let randomString2 = String(Math.round(Math.random())); //0 or 1
    return Promise.resolve([randomString1, randomString2]);
}

function getKeyToBeTested() {   
    //same as in 'getAllowedKeys' 
    let randomString = String(Math.round(Math.random())); //0 or 1
    return Promise.resolve(randomString);        
}

Promise.all([getAllowedKeys(), getKeyToBeTested()]).then((results) => {    
    let allowedKeys: string[] = results[0];
    let keyTobeTested: string = results[1]; //'0' or '1'
    let mcuParams = {};

    for (let entry of results[0]) { //create dictionary dynamically     
        mcuParams[entry] = ''; //the value assigned is indiferent        
    }

    //create type dynamically. in this example, it could be '0', '1' or '0' | '1'
    type McuParams = keyof typeof mcuParams; 

    //create Type Guard based on allowedKeys fetched from somewhere
    function isMcuParams(value:string) : value is McuParams { 
        return mcuParams.hasOwnProperty(value);
    }

    function change(key: McuParams) { 
        //do something
        alert('change function executed: [' + allowedKeys.toString() + '] - ' + keyTobeTested);                
    }             

    if (isMcuParams(keyTobeTested)) {
        change(keyTobeTested);
    }
    else {
        alert('change function not executed: [' + allowedKeys.toString() + '] - ' + keyTobeTested);        
     }
});

答案 2 :(得分:0)

更新:

根据我提供的最新理解和您提供的背景信息,这是与您的用例相关的代码段吗?如果是这样,它对我来说很好。

interface McuParams {
    foo: string;
    bar: string;
};

function change(key: keyof McuParams, dispatch: Function) {
    if (typeof key === 'foo') {
        console.log('call foo()');
    } else if (typeof key === 'bar') {
        console.log('call bar()');
    }
}

function callback(data) {
    change(data, this.props.dispatch)
}