簡體   English   中英

Typescript:在條件語句中使用條件鍵入

[英]Typescript: using conditional typing in conditional statements

假設我有很多工會類型:

var MyComplexType = MyType1 | MyType2 | MyType3 | ... | MyTypeN

MyType{N}具有這種簽名:

type MyType1 = {
    type: string,
    data: <different data for different types>
}

我知道我可以使用一種類型保護功能,例如:

function isMyComplexTypeOfMyType1(item: MyComplexType): item is MyType1 {
    return item.type == "type of MyType1"
}

但是在這種情況下,我應該編寫很多此類函數。

因此,問題是:我可以在條件語句中動態定義類型( if ... else還是switch ... case )? 例如:

function someFunction(item: MyComplexType) {
    switch (item.type) {
        case "type of MyType1":
            // item is MyType1
            // do something
            break
        case "type of MyType2":
            // item is MyType2
            // do something
            break
        ...
    }
}

如果計划使用switch/case語句檢查並集類型化的值,則可能應使其成為可區分的並集 ,其中該並集的每個組成部分的type屬性都聲明為相關的字符串文字,而不是僅是string 您實際上並不需要條件類型來處理此問題,至少不需要在someFunction()實現中進行處理。

例如,假設您的類型如下所示:

type MyType1 = { type: "type1", data: { a: string, b: number } };
type MyType2 = { type: "type2", data: { c: boolean, d: string } };
type MyType3 = { type: "type3", data: { e: number, f: boolean } };

type MyComplexType = MyType1 | MyType2 | MyType3;

然后,編譯器將自動將對MyComplexType["type"]檢查視為類型保護,如下所示:

const exhaustivenessCheck = (x: never) => x;

function someFunction(item: MyComplexType) {
    switch (item.type) {
        case "type1":
            console.log(2 * item.data.b); // okay
            break;
        case "type2":
            console.log(item.data.d.charAt(0)); // okay
            break;
        case "type3":
            console.log(7 - item.data.e); // okay
            break;
        default:
            throw exhaustivenessCheck(item); // okay
    }
}

如果該函數某種程度上落入default則該exhaustivenessCheck()基本上是throw語句。 那不應該發生,但是有用的是,如果編譯器不認為您檢查了所有內容,就會警告您。 這是因為exhaustivenessCheck()要求其參數的類型必須是never ,這是不可能發生的。 如果您將case "type3"子句注釋掉,或者稍后在MyComplexType聯合中添加新的成分,則exhaustivenessCheck()行將引發錯誤,表明您無法檢查案例。


此時,您可以停止操作,但是如果您的類型確實是編程的,因為它們僅包含兩個屬性( type判別字符串和data屬性),那么您可以使用更少的重復來定義類型,如下所示:

// a mapping from type string to data type
type MyTypes = {
    type1: { a: string, b: number };
    type2: { c: boolean, d: string };
    type3: { e: number, f: boolean };
}

// convert the mapping to the union of types
type MyType<K extends keyof MyTypes = keyof MyTypes> = {
    [P in K]: { type: P, data: MyTypes[P] }
}[K]

可以驗證MyTypeMyType<keyof MyTypes>擴展為MyComplexType予如上所定義的結合。 您以前的MyType1現在是MyType<"type1"> ,依此類推。 也就是說,如果您需要使用舊名稱作為類型,則可以這樣操作:

type MyType1 = MyType<"type1">;
type MyType2 = MyType<"type2">;
type MyType3 = MyType<"type3">
type MyComplexType = MyType;

希望能有所幫助; 祝好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM