typescript - Bästa sättet att ange ärvt-klassens returtyp


Låt oss säga att jag har en basklass Animal:

class Animal {
  name: string;

  eat(): void;
  sleep(): void;
  
  constructor(name: string) {
    this.name = name;
  }
}

Och jag kan potentiellt ha ett stort antal underklasser, t.ex.,

class Dog extends Animal {
  bark(): void;

  constructor(name: string) {
    super(name);
  }
}

class Cat extends Animal {
  meow(): void;

  constructor(name: string) {
    super(name);
  }
}

class Mouse extends Animal {
// ... and so on

och jag har en funktion som returnerar ett barn av Animal som är okänt vid kompileringstid, hur bör jag definiera returtypen bortsett från att göra Dog | Cat | Mouse | ... eller any?

const getAnimalByName(name: string) : /* what goes here? */ {
  /* ... */
};

Jag antar att om jag specificerar Animal och använder det Animal-objektet senare, kan jag stöta på fel som "Property bark() finns inte på typen ..." om jag anropar getAnimalByName('dog');. Finns det ett sätt att specificera en returtyp som tillåter denna flexibilitet?

Svar #1

Vi skulle kunna använda funktionsöverladdning. Nackdelen är att du måste uppdatera överlagringarna manuellt varje gång du lägger till eller tar bort en djurtyp.

class Animal {
  name: string;

  eat() {};
  sleep() {};
  
  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  bark() {};

  constructor(name: string) {
    super(name);
  }
}

class Cat extends Animal {
  meow() {};

  constructor(name: string) {
    super(name);
  }
}

function getAnimalByName(name: 'dog'): Dog;
function getAnimalByName(name: 'cat'): Cat;
function getAnimalByName(name: string) {
  switch (name) {
    case 'dog':
      return new Dog('dog');
    case 'cat':
      return new Cat('cat');
  }
  return null;
}

const animal = getAnimalByName('dog');
// => Dog

lekplats