En TypeScript, ¿cómo puedo verificar el tipo de un objeto y ramificarme según ese tipo?
const createAnimalForId(animalId: AnimalIdsEnum): CatAnimal | BirdAnimal { // animalData has type: CatAnimalData | BirdAnimalData | undefined const animalData = animalsMap.get(animalId); // Q: How can I check the type here? if(animalData "is of type" CatAnimalData) { // NB: I want it to be aware that animalData here is of type CatAnimalData return new CatAnimal(animalData); } // Q: How can I check the type here? else if(animalData "is of type" BirdAnimalData) { // NB: I want it to be aware that animalData here is of type BirdAnimalData return new BirdAnimal(animalData); } else { throw new RangeError("Animal type not recognised"); } } NB: CatAnimal y BirdAnimal heredan de AbstractAnimal .
¿Cómo puedo comprobar el tipo de un objeto?
Dado que estos tipos se implementan como class es, solo puede usar la instanceof de:
if (animalData instanceof CatAnimalData) { … } if (animalData instanceof BirdAnimalData) { … }… y ramificarse en función de ese tipo?
No. Este es un diseño feo, no extensible. En su lugar, haga que todas sus entradas implementen un toAnimal o getAnimal o createAnimal , y luego simplemente llame a eso:
export class AbstractAnimalData { name: string; abstract createAnimal(): Animal { throw new RangeError("Animal type not recognised"); } } export class CatAnimalData extends AbstractAnimalData { favouriteFood: string; // NB: Leaving out the constructor for brevity createAnimal(): CatAnimal { return new CatAnimal(this); } } export class BirdAnimalData extends AbstractAnimalData { archEnemy: string; // NB: Leaving out the constructor for brevity createAnimal: BirdAnimal { return new BirdAnimal(animalData); } }después
function createAnimalForId(animalId: AnimalIdsEnum): Animal { const animalData = animalsMap.get(animalId); if (!animalData) { throw new RangeError(`AnimalId '${animalId}' not supported`); } return animalData.createAnimal(); // ^^^^^^^^^^^^^^^ }Puede verificar si la propiedad existe en animalType
const createAnimalForId(animalId: AnimalIdsEnum): CatAnimal | BirdAnimal { // animalData has type: CatAnimalData | BirdAnimalData | undefined const animalData = animalsMap.get(animalId); if('favouriteFood' in animalData) { // CatAnimalData return new CatAnimal(animalData); } else if("archEnemy" in animalData) { //BirdAnimalData return new BirdAnimal(animalData); } else { throw new RangeError("Animal type not recognised"); } }Una solución que se me ocurre sería la siguiente. Sin embargo, esto tiene el problema de que, dentro de los casos condicionales, TypeScript no es consciente del tipo específico de animalData .
Según tengo entendido, esto significa que tendría que lanzarlo manualmente, lo que no creo que sea lo ideal.
const createAnimalForId(animalId: AnimalIdsEnum): CatAnimal | BirdAnimal { // animalData has type: CatAnimalData | BirdAnimalData | undefined const animalData = animalsMap.get(animalId); if(animalData.type === animalType.catAnimal) { // Problem: TypeScript is not aware of the specific type of animalData here return new CatAnimal( animalData // as CatAnimalData ); } else if(animalData.type === animalType.birdAnimal) { // NB: I want it to be aware that animalData here is of type BirdAnimalData return new BirdAnimal( animalData // as BirdAnimalData ); } else { throw new RangeError("Animal type not recognised"); } }