Generic Classes
Generic classes allow you to define classes that can work with a variety of types.
ts
// genericClasses.ts// A generic class for a simple data storageclassDataStorage <T > {privatedata :T [] = [];addItem (item :T ): void {this.data .push (item );}removeItem (item :T ): void {this.data = this.data .filter ((i ) =>i !==item );}getAllItems ():T [] {return [...this.data ];}}// Re-using the methods from the generic class but with different types// with stringslettextStorage = newDataStorage <string>();textStorage .addItem ("Hello");textStorage .addItem ("World");textStorage .removeItem ("Hello");console .log (textStorage .getAllItems ()); // ['World']// with numbersletnumberStorage = newDataStorage <number>();numberStorage .addItem (1);numberStorage .addItem (2);numberStorage .removeItem (1);console .log (numberStorage .getAllItems ()); // [2]
Let's look at this line by line
class DataStorage<T> {
- We defined a class named
DataStorage
that accepts a single generic type, represented by<T>
private data: T[] = [];
-
The class has a property named
data
, which is an array of the generic type<T>
that we defined earlier. We initiated data with an empty array to start= [];
-
The
private
keyword denotes that we cannot directly access thedata
property from outside the class and manipulate it. We must use the methods defined in the class to add or remove data from the array.
We then defined two methods addItem()
and removeItem()
to manipulate the data
property of the class.
ts
addItem(item: T): void {this.data.push(item);}removeItem(item: T): void {this.data = this.data.filter(i => i !== item);}
- Both these methods accept an item of the generic type
T
as an input parameter. This is the same generic type as the<T>
we specified when defining the Class.
We then defined a method to fetch all the items from data
and return them as an array of the same type as <T>
by explicitly stating the return type as : T[]
ts
getAllItems(): T[] {return [...this.data];}
Now we are able to re-use this Generic Class to store different types of data types, but have access to the same methods on both
ts
// Same Class, Different Data Typeslet textStorage = new DataStorage<string>();let numberStorage = new DataStorage<number>();// addItem() and other methods are common to bothtextStorage.addItem("Hello");numberStorage.addItem(2);
Being able to use a Generic Class saved us the effort of needing to write separate classes for string and number storage.
We could have used a Common class with a union type allowing for both numbers and strings and in some cases this may be easier, but it's generally preferred to use the generic class because it can be extended to cover more types easily without modification to the internal methods.
In summary, while union types can be straightforward for specific scenarios, generics offer a more scalable solution, especially when dealing with a broader range of types.