簡體   English   中英

模式匹配 switch 語句

[英]Pattern matching switch statements

假設我有返回動物信息的 API。 然而,json 有效載荷對於每種動物來說差異很大,即使許多屬性是共同的和強制性的。

我想為這些不同的動物中的每一種都“強輸入”typescript class,這樣我的代碼就不會變得一團糟。 每只動物都需要非常獨特和特定的處理方式!

這樣做的正確方法是什么? 基本上我想完成這樣的事情:

interface Animal {
    Name: string;
    Weight: number;
}

interface Insect extends Animal {
    AmountOfEyes: number;
}

interface Bird extends Animal {
    PlumageColor : string;
}

function OnlyForBirds(bird: Bird)
{
     // do something birdly
}

function OnlyForInsects(insect: Insect)
{
     // do something creepy
}


function GetAnimal(animalId: string) : Promise<Animal>
{
    const uri = `${baseURL}/${animalId}`;

    // fetches the json response body from http request
    const result = await get<any>(uri); 

    switch(animal.Name)
    {
        case  'Insect':
            return result as Insect;
        case ...
            ...
    }

    // throw unhandled
}

function ProcessAnimal(animalId:string) : Promise
{
    let animal = await GetAnimal(animalId);
 
    // how do I do this now? Can't I use something over tye interface
    // types instead of using the .Name and casting again?
    // is there any advisable standard I can use?

    if(animal is a bird){  
        OnlyForBirds(bird)
    }

    else if(animal is an insect){
        OnlyForInsects(insect)
    }
}

任何建議,包括不使用這樣的界面,都值得贊賞。

對於您的用例,您發布的答案可能是最好的解決方案。 我只是想用不同的方法來插話。 如果您想擁有多層 inheritance,您的解決方案開始崩潰,其中Duck擴展了Bird 如果要查找Animal是否與基本Bird接口匹配,可以定義自定義類型保護function 來查看 object 的屬性以查看它是否具有PlumageColor 如果是這樣,那么 typescript 知道可以將其用作Bird

這是基本版本。 我們說animal有一個可選的屬性PlumageColor以便我們可以無錯誤地訪問它,即使它是undefined 然后我們檢查PlumageColor是否已定義並且它是一個string

const isBird = (animal: Animal & {PlumageColor?: any}): animal is Bird => {
  return typeof animal.PlumageColor === "string";
}

這個帶有generics的版本更好,因為它斷言animalBird同時還保留了已經知道的關於animal的任何其他類型信息。

const isBird = <T extends Animal & {PlumageColor?: any}>(animal: T): animal is T & Bird => {
  return typeof animal.PlumageColor === "string";
}

我想到了。 一些深邃的黑暗魔法。 在基本接口中定義一個枚舉屬性。 每個新的不同類型的 class,或在這種情況下為動物,都為自己分配這些屬性之一。 打開這個屬性,在開關中你有你輸入的動物

enum AnimalType {
    Insect = "Insect",
    Bird = "Bird"
}

interface Animal {
    Type: AnimalType;
    Weight: number;
}

interface Insect extends Animal {
    Type: AnimalType.Insect; // MAGIC BREWING
    AmountOfEyes: number;
}

interface Bird extends Animal {
    Type: AnimalType.Bird; // MAGIC BREWING
    PlumageColor : string;
}

function OnlyForBirds(bird: Bird)
{
     // do something birdly
}

function OnlyForInsects(insect: Insect)
{
     // do something creepy
}


function GetAnimal(animalId: string) : Promise<Animal>
{
    const uri = `${baseURL}/${animalId}`;

    // fetches the json response body from http request
    const result = await get<any>(uri); 

    switch(animal.Type)
    {
        case  'Insect':
            return result as Insect;
        case ...
            ...
    }

    // throw unhandled
}

function ProcessAnimal(animalId:string) : Promise
{
    let animal = await GetAnimal(animalId);

    switch(animal.AnimalType){
        case AnimalType.Insect:
            OnlyForInsects(animal); // within this case clause, animal is typed as an Insect! MAGIC!
            break;
        
        case AnimalType.Bird:
            OnlyForBirds(animal); // within this case clause, animal is typed as an bird! Go free little bird!
            break;

        default:
            // throw
    }
}

暫無
暫無

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

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