ค้นหาเว็บไซต์

typescript - วิธีเขียนการรักษาประเภทที่ผู้ใช้กำหนดสำหรับ "string" | "literal" | "types"?


ฉันมีฟังก์ชันดังต่อไปนี้:

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 ของฉันกำลังส่งอะไรในเวลาคอมไพล์ อย่างไรก็ตาม การป้องกันประเภทที่ผู้ใช้กำหนดขึ้นบางครั้งสามารถใช้เพื่ออนุมานข้อมูลประเภทในเวลารันไทม์และส่งข้อมูลนั้นไปยังคอมไพเลอร์ผ่านเงื่อนไขได้

เป็นไปได้หรือไม่ที่จะเขียนตัวป้องกันประเภทที่กำหนดเองสำหรับประเภทสตริง keyof เช่น keyOf foo เมื่อ foo ถูกกำหนดเป็นเพียงประเภทเท่านั้น (ไม่ใช่ในอาร์เรย์)? ถ้าเป็นไปได้ ทำอย่างไร?

คำตอบ #1

นี่คือตัวอย่าง:

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 (เช่น if หรือ throw เป็นต้น)

คำตอบ #2

ลองทำตามนี้:

 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);        
     }
});

บทความที่เกี่ยวข้อง