Typescript 模式匹配开关语句

Typescript 模式匹配开关语句,typescript,typescript-generics,react-typescript,Typescript,Typescript Generics,React Typescript,假设我有返回动物信息的API。然而,每种动物的json有效载荷都有很大差异,即使许多属性是通用的和强制性的 我想为这些不同的动物中的每一个创建一个“强类型”类型脚本类,这样我的代码就不会变得一团糟。每种动物都需要非常独特和具体的处理 正确的做法是什么?基本上,我想完成以下任务: interface Animal { Name: string; Weight: number; } interface Insect extends Animal { AmountOfEyes

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

界面动物{ 名称:字符串; 重量:个数; } 昆虫与动物的界面{ 是:数字; } 鸟类与动物的接口{ 羽毛颜色:弦; } 功能仅适用于鸟(鸟:鸟) { //做傻事 } 功能仅适用于昆虫(昆虫:昆虫) { //做些令人毛骨悚然的事 } 函数GetAnimal(animalId:string):Promise { 常量uri=`${baseURL}/${animalId}`; //从http请求获取json响应正文 const result=等待获取(uri); 开关(动物名称) { “昆虫”一案: 返回结果为昆虫; 案例 ... } //未经处理的抛掷 } 函数ProcessAnimal(animalId:string):Promise { 让动物=等待得到动物(动物); //我现在该怎么做?我不能通过tye接口使用一些东西吗 //键入而不是使用.Name并再次强制转换? //有什么可取的标准我可以使用吗? 如果(动物是鸟){ 仅鸟(鸟) } 否则,如果(动物是昆虫){ 仅限昆虫类 } }
任何建议,包括不要使用这样的接口,我都会很感激。

我想出来了。一些很深的黑暗魔法。 在基本接口中定义枚举属性。每一个新的不同类型的类,或者在本例中的动物,都会为自己指定这些属性中的一个。打开此属性,并在该属性中键入动物

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
    }
}
enum AnimalType{
昆虫=“昆虫”,
Bird=“Bird”
}
界面动物{
类型:动物型;
重量:个数;
}
昆虫与动物的界面{
类型:AnimalType.昆虫;//神奇酿造
是:数字;
}
鸟类与动物的接口{
类型:AnimalType.Bird;//魔法酿造
羽毛颜色:弦;
}
功能仅适用于鸟(鸟:鸟)
{
//做傻事
}
功能仅适用于昆虫(昆虫:昆虫)
{
//做些令人毛骨悚然的事
}
函数GetAnimal(animalId:string):Promise
{
常量uri=`${baseURL}/${animalId}`;
//从http请求获取json响应正文
const result=等待获取(uri);
开关(动物型)
{
“昆虫”一案:
返回结果为昆虫;
案例
...
}
//未经处理的抛掷
}
函数ProcessAnimal(animalId:string):Promise
{
让动物=等待得到动物(动物);
开关(动物。动物类型){
案例动物类型。昆虫:
OnlyForInsects(animal);//在这个case子句中,animal被键入为昆虫!MAGIC!
打破
案例动物类型。鸟类:
onlyforbird(animal);//在这个case子句中,animal被键入为bird!放开小鸟!
打破
违约:
//扔
}
}

对于您的用例,您发布的答案可能是最好的解决方案。我只是想用一种不同的方法来插话。如果您想要有多个继承层,那么您的解决方案开始崩溃,其中
Duck
扩展
Bird
。如果要查找
动物
是否与基本
界面匹配,可以定义一个自定义函数,查看对象的属性,查看对象是否具有
羽毛颜色
。如果是这样,那么typescript就知道可以将其用作

这是基本版本。我们说
animal
有一个可选属性
PlumageColor
,这样即使
未定义
,我们也可以无误地访问它。然后我们检查
PlumageColor
是否已定义,并且它是
字符串

const isBird = (animal: Animal & {PlumageColor?: any}): animal is Bird => {
  return typeof animal.PlumageColor === "string";
}
此版本更好,因为它断言
动物
,同时还保留了关于
动物
的任何其他类型信息

const isBird = <T extends Animal & {PlumageColor?: any}>(animal: T): animal is T & Bird => {
  return typeof animal.PlumageColor === "string";
}
const-isBird=(动物:T):动物是T&Bird=>{
返回typeof animal.PlumageColor==“string”;
}