Generics serve as an essential tool in TypeScript, allowing developers to create flexible and reusable components that work with varying data types while maintaining strong type safety. In this article, we’ll break down what generics are, how they operate, and provide practical examples to illustrate their utility.
Generics are a way to create components that can handle different data types while still enforcing type constraints. You can think of generics as templates to write code that works independently of the data type. Instead of specifying a single type, you define a placeholder that can be replaced with any valid type during function or class instantiation.
The syntax for defining generics in TypeScript involves using angle brackets <T>
to define a type parameter. Here’s a basic example of a generic function:
function identity<T>(arg: T): T { return arg; } let result1 = identity<string>("Hello, Generics!"); // result1 is of type string let result2 = identity<number>(42); // result2 is of type number
In this example, identity
is a generic function that takes a parameter arg
of type T
and returns a value of the same type. Note how we specify the type when calling the function.
Generics can also accept multiple type parameters. This is useful when you need to work with pairs of types:
function pair<U, V>(first: U, second: V): [U, V] { return [first, second]; } let result3 = pair<string, number>("Age", 30); // result3 is of type [string, number]
Here, the pair
function takes two parameters of potentially different types and returns a tuple containing both values.
Interfaces can also leverage generics, allowing you to define flexible data structures. Here’s an example of a generic interface:
interface Container<T> { value: T; } let numberContainer: Container<number> = { value: 123 }; let stringContainer: Container<string> = { value: "Generics" };
In this case, Container<T>
can accommodate any type, maintaining type safety when you specify what type of value is being held.
You can utilize generics within classes. This follows a similar structure as functions and interfaces:
class Box<T> { private items: T[] = []; add(item: T): void { this.items.push(item); } get(index: number): T | undefined { return this.items[index]; } } let stringBox = new Box<string>(); stringBox.add("Hello"); console.log(stringBox.get(0)); // Outputs: Hello let numberBox = new Box<number>(); numberBox.add(123); console.log(numberBox.get(0)); // Outputs: 123
In this example, the Box
class can store items of any specific type decided during instantiation, either strings or numbers, promoting reusability.
While generics offer flexibility, sometimes you need to impose constraints to ensure your generic types satisfy certain conditions. Use the extends
keyword for constraining a type parameter:
function logLength<T extends { length: number }>(item: T): void { console.log(item.length); } logLength("Hello, Generics!"); // Works because string has a length property logLength([1, 2, 3]); // Works because arrays have a length property // logLength(42); // Error: Argument of type 'number' is not assignable to parameter of type '{ length: number; }'
This function accepts any type T
that has a length
property, thereby ensuring it can log the length of the passed argument.
TypeScript allows you to declare default types for generics. This helps simplify your code when a common type can be inferred:
function wrap<T = string>(value: T): T { return value; } let wrappedValue = wrap(100); // The inferred type is number let wrappedString = wrap(); // The inferred type is string by default
In this example, wrap
defaults to type string
unless another type is provided.
Generics in TypeScript provide a powerful means of building type-safe and reusable components. By utilizing generics, you can enhance your code’s flexibility and maintainability while ensuring strong type checks help to catch errors early in the development process. With the concepts and examples in this blog, you should feel equipped to harness generics in your own TypeScript projects effectively.
17/10/2024 | TypeScript
17/10/2024 | TypeScript
17/10/2024 | TypeScript
17/10/2024 | TypeScript
17/10/2024 | TypeScript
17/10/2024 | TypeScript
17/10/2024 | TypeScript
17/10/2024 | TypeScript