When working with arrays containing different types in TypeScript, I often encounter issues with properties that are not present on all types.
The same challenge arises when dealing with various sections on a page, different user roles with varying properties, and so forth.
For instance, let's consider an example involving animals:
Suppose we have types for Cat, Dog, and Wolf:
export type Cat = {
animal: 'CAT';
legs: 4;
}
export type Dog = {
animal: 'DOG',
legs: 4,
requiresWalks: true,
walkDistancePerDayKm: 5
}
export type Wolf = {
animal: 'WOLF',
legs: 4,
requiresWalks: true,
walkDistancePerDayKm: 20
}
type Animal = Cat | Dog | Wolf;
const animals: Animal[] = getAnimals();
animals.forEach(animal => {
// Here, the goal is to check if the animal requires a walk
if (animal.requiresWalks) {
// Error: Property 'requiresWalks' does not exist on type 'Animal'. Property 'requiresWalks' does not exist on type 'Cat'.
goForAWalkWith(animal)
}
});
// The type "AnimalThatRequiresWalks" does not exist, and I need guidance on how to set it up
goForAWalkWith(animal: AnimalThatRequiresWalks) {
}
As noted above, using the property requiresWalks to narrow down the type results in errors.
Moreover, when dealing with a larger number of animals, designing types that can extend animals—such as "AnimalThatRequiresWalks" with multiple properties related to walking animals—poses challenges.
How can I cleanly merge these types with "AnimalThatRequiresWalks" (having properties "requiresWalks true" and "walkDistancePerDayKm") and effectively narrow it down to "AnimalThatRequiresWalks"?