对象中对象的高级类型

Advanced Types in Object in Object

我不知道如何在对象中使用多个高级类型。 我在父组件中有一个对象 Animal 并且在某些情况下起作用,我必须显示与特定类型相关的子组件;但我有以下错误,不知道解决方案。

interface Animal {
  name: string;
  age: number;
  type: Bird | Fish;
}

interface Bird {
  fly(): void;
}
 
interface Fish {
  swim(): void;
}

Property 'swim' does not exist on type 'Bird | Fish'. Property 'swim' does not exist on type 'Bird'.

我试图在 typescript doc 中找到一些东西,但我没有找到任何解决方案。

高级示例:

interface.ts:

interface Animal {
  id: number;
  code: string;
  metadata: Bird | Fish;
}

interface basicForm {
  formLabel: string;
}

interface Bird extends basicForm {
  name: string;
  age: number;
  fly: string;
}
 
interface Fish extends basicForm {
  name: string;
  age: number;
  swim: string;
}

父组件html:

<ng-container [ngSwitch]="formLabel">
  <app-fish-form *ngSwitchCase="'fishForm'" [detail]="detail"></app-fish-form>
  <app-bird-form *ngSwitchCase="'birdForm'" [detail]="detail"></app-bird-form>
</ng-container>

父组件 ts:

public detail: Animal;

constructor() { }

ngOnInit() {
  this._checkForm();
}

private _checkForm() {
  // res should be fishForm or birdForm
  *backendCall*then(res => this.detail.metadata.formLabel = res)
}

子组件(鱼)html:

<input type="text" name="swim" [(ngModel)]="detail.swim" />

子组件(鱼)ts:

@Input() detail: Animal;

ngOnInit() {
  this.detail.metadata.swim = 'yes';
}

在我看来,如果在子组件的初始化时我能够将 this.detail.metadata as Fish;

我不知道你为什么直接在 type 上呼叫 swim()fly()。继承用于根据其类型以不同的方式实现相同的方法。

下面我会给你一个类似于你正在做的解决方案,但它意味着是你的接口的包装器而不是它们应该继承的父 class .

继承主要是为了做这样的事情:

interface Animal {
  name: string;
  code: string;
  move: ()=> void;
}

class Fish implements Animal {
  name: string;
  code: string;
  constructor(name: string, code: string) {
    this.name = name;
    this.code = code;
  }
  move() {
    console.log("I'm swimming...");
  }
}
 
class Bird implements Animal {
   name: string;
   code: string;
   constructor(name: string, code: string) {
    this.name = name;
    this.code = code;
  }
  move() {
    console.log("I'm flying...");
  }
}

如您所见,鸟类和鱼类都执行相同的方法move(),但它们的行为不同。这是继承的主要目的,“最终”继承对象通常是 class 而不是接口。

另一方面,如果您只需要一个 wrapper 用于一系列 classes,而不是使用继承,我建议您采用这种方法:

interface Bird {
  name: string
  age: number
  type: 'BIRD'
  fly: ()=>void
}
 
interface Fish {
  name: string
  age: number
  type: 'FISH'
  swim: ()=>void
}

type Animal = Fish | Bird;

let my_animal: Animal = {
  name: 'Karl'
  age: 8
  type: 'FISH' as 'FISH'
  swim: () => { console.log("I'm swimming...") }
}

if(my_animal.type === 'FISH'){
  my_animal.swim(); //Typescript will not complain here
}

在这种情况下,动物充当包装纸。