Typescript Generics

Jennifer  Watanabe
Jennifer WatanabeWednesday, January 11, 2023
Typescript Generics

If you’re learning TypeScript you’ve probably came across Generics. Generics are a way to pass types just like you would pass parameters. The benefits of using Generics is that you can make reusable components that accept different types and are therefore also type safe. Generics are not the same as the any type since you will be telling TypeScript what type your Generic is when you pass it in.

First let’s declare an object that we want to use:

interface DogBreed { averageHeight: number[]; isGoodDoggo: boolean; name: string; } // An object that satisfies the DogBreed type const maltese: DogBreed = { averageHeight: [7, 8, 9], isGoodDoggo: true, name: "Maltese", };

Now let’s make a class that uses the DogBreed type:

// A class that accepts dogs and keeps track of them class DogKennel { dogs: DogBreed[] = []; // A function within DogKennel that accepts an object of the type DogBreed and adds it to the dogs array admitDog(newDog: DogBreed) { this.dogs.push(newDog); } // A function within DogKennel that logs the dogs array to the console getAllDogs() { if (!this.dogs.length) { console.log("The Kennel currently has no dogs."); return; } console.log("The Kennel currently has the following dogs:"); console.log(this.dogs); } }

With the DogKennel class we can create as many DogKennels as we want and admit some dogs!

const PetStoreKennel = new DogKennel(); PetStoreKennel.admitDog(maltese); PetStoreKennel.admitDog(maltese); PetStoreKennel.getAllDogs(); const VeterinarianKennel = new DogKennel(); VeterinarianKennel.getAllDogs(); const FosterHomeKennel = new DogKennel(); FosterHomeKennel.admitDog(maltese); FosterHomeKennel.getAllDogs();

This is great if all we had in the world were dogs. But what about these animals?

// An object that satisfies the CatBreed type const tabbyCat: CatBreed = { isKindOfMean: true, mostRecentlyDestroyedObject: "couch", name: "Tabby Cat", }; // An object that satisfies the ReptileBreed type const redFootedTortoise: ReptileBreed = { diet: ["vegetables", "fruit", "hay", "berries"], lifeSpan: 50, name: "Tortoise", }; // An object that satisfies the BirdBreed type const cockatiel: BirdBreed = { canWhistle: true, name: "Pretty Bird", primaryColor: "#d2e75f", };

How can we rewrite DogKennel to accept these other animals? With Generics we can pass the type we want the class to accept.

class Kennel<SomeAnimalBreed> { animals: SomeAnimalBreed[] = []; admitAnimal(newAnimal: SomeAnimalBreed) { this.animals.push(newAnimal); } getAllAnimals() { if (!this.animals.length) { console.log("The Kennel currently has no animals."); return; } console.log("The Kennel currently has the following animals:"); console.log(this.animals); } } const PetStoreKennel = new Kennel<DogBreed | CatBreed | ReptileBreed | BirdBreed>(); PetStoreKennel.admitAnimal(maltese); PetStoreKennel.admitAnimal(tabbyCat); PetStoreKennel.admitAnimal(redFootedTortoise); PetStoreKennel.admitAnimal(cockatiel);

This allows us to add type safety to our classes. So if we tried to add a non-animal to Kennel we would get an error:

// An object that satisfies the type Vehicle const camry: Vehicle = { make: "Toyota", model: "Camry", numberOfWheels: 4, }; // This causes an error: // Argument of type 'Vehicle' is not assignable to parameter of type 'DogBreed | CatBreed | ReptileBreed | BirdBreed'. PetStoreKennel.admitAnimal(camry);

Because SomeAnimalBreed is just a name for a type we can replace it like this:

class Kennel<Type> { animals: Type[] = []; admitAnimal(newAnimal: Type) { this.animals.push(newAnimal); } ...

But often you’ll see it simplified even further with a T:

class Kennel<T> { animals: T[] = []; admitAnimal(newAnimal: T) { this.animals.push(newAnimal); } ...

You can simplify things further by extending the different Breed interfaces to something even more generalized like Animal type and pass that as the Generic to Kennel like this: const PetStoreKennel = new Kennel<Animal>();

Read my Beginner Blog on TypeScript:

Read more about Generics:

Share this post


Related Posts:

Interested in working with us?

Give us some details about your project, and our team will be in touch with how we can help.

Get in Touch