首页 > 解决方案 > 模式匹配 switch 语句

问题描述

假设我有返回动物信息的 API。但是,对于每种动物,json 有效负载差异很大,即使许多属性是常见的和强制性的。

我想为这些不同的动物中的每一种都有“强类型”的打字稿类,这样我的代码就不会变得一团糟。每只动物都需要非常独特和特定的处理方式!

这样做的正确方法是什么?基本上我想完成这样的事情:

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

任何建议,包括不使用这样的界面,都值得赞赏。

标签: typescripttypescript-genericsreact-typescript

解决方案


对于您的用例,您发布的答案可能是最好的解决方案。我只是想用不同的方法来插话。如果您想拥有多层继承,您的解决方案就会开始崩溃,其中Duckextends Bird。如果要查找 是否Animal与基Bird接口匹配,可以定义一个自定义类型保护函数,该函数查看对象的属性以查看它是否具有PlumageColor. 如果是这样,那么 typescript 就知道可以将其用作Bird.

这是基本版本。我们说它animal有一个可选属性PlumageColor,这样即使它是undefined. 然后我们检查它PlumageColor是否已定义,它是一个string.

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

这个带有泛型的版本更好,因为它断言animal同时Bird还保留了已经知道的任何其他类型信息animal

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

推荐阅读