【问题标题】:Pattern matching switch statements模式匹配 switch 语句
【发布时间】:2021-04-26 14:49:51
【问题描述】:

假设我有返回动物信息的 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)
    }
}

感谢您提出任何建议,包括不使用此类界面。

【问题讨论】:

    标签: typescript typescript-generics react-typescript


    【解决方案1】:

    对于您的用例,您发布的答案可能是最佳解决方案。我只是想用不同的方法来插话。如果您想拥有多层继承,您的解决方案就会开始崩溃,其中Duck 扩展Bird。如果您想查找Animal 是否与基本Bird 接口匹配,您可以定义一个自定义type guard 函数来查看对象的属性以查看它是否具有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";
    }
    

    【讨论】:

      【解决方案2】:

      我想通了。一些深邃的黑暗魔法。 在基本接口中定义一个枚举属性。每个新的不同类型的类,或在这种情况下的动物,都为自己分配了这些属性之一。打开这个属性,在开关中你有你输入的动物

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-18
        • 1970-01-01
        • 1970-01-01
        • 2011-02-23
        相关资源
        最近更新 更多