将变量定义为 TypeScript 中可区分联合的一种变体

Defining a variable as one variant of a discriminated union in TypeScript

我有以下打字稿代码,它使用可区分的联合来区分一些相似的对象:

interface Fish  {
  type: 'FISH',
}

interface Bird  {
  type: 'BIRD',
  flyingSpeed: number,
}

interface Ant  {
  type: 'ANT',
}

type Beast = Fish | Bird | Ant

function buildBeast(animal: 'FISH' | 'BIRD' | 'ANT') {
    const myBeast: Beast = animal === 'BIRD' ? {
        type: animal,
        flyingSpeed: 10
    } : {type: animal}
}

在函数 buildBeast 中,它接受一个符合我的 Beast 类型的所有可能 types 的字符串,但它不允许我声明 myBeast作为类型 Beast 由于此错误:

Type '{ type: "BIRD"; flyingSpeed: number; } | { type: "FISH" | "ANT"; }' is not assignable to type 'Beast'.
  Type '{ type: "FISH" | "ANT"; }' is not assignable to type 'Beast'.
    Type '{ type: "FISH" | "ANT"; }' is not assignable to type 'Ant'.
      Types of property 'type' are incompatible.
        Type '"FISH" | "ANT"' is not assignable to type '"ANT"'.
          Type '"FISH"' is not assignable to type '"ANT"'.

似乎所有情况仍然会产生正确的 Beast 但 TS 似乎无法强制转换不同的类型。有什么想法吗?

TypeScript 不会control flow analysis by walking through union types and making sure that each type works. It would be nice if it did so or if you could tell it to do so, and in fact I've made a suggestion达到那种效果,但目前不可能。

目前,我所知道的处理它的唯一方法是我在该建议中提到的解决方法:要么进行类型断言(这是不安全的),要么让编译器遍历不同的情况(这是多余的) ).以下是两种不同的方式:

断言:

function buildBeast(animal: 'FISH' | 'BIRD' | 'ANT') {
  const myBeast: Beast = animal === 'BIRD' ? {
    type: animal,
    flyingSpeed: 10
  } : {type: animal} as Fish | Ant;
}

通过不同的案例遍历编译器:

function buildBeast(animal: 'FISH' | 'BIRD' | 'ANT') {
  const myBeast: Beast = animal === 'BIRD' ? {
    type: animal,
    flyingSpeed: 10
  } : (animal === 'FISH') ? { 
    type: animal 
  } : { type: animal };
}

嘿,如果您认为 TypeScript 应该允许您在联合类型上分发控制流分析,也许可以转向那个建议并给出它或描述您的用例。或者,如果上述解决方案对您有用,那也很好。

希望对您有所帮助。祝你好运!