Generics Basics
A key part of software engineering is building reusable components. Generics allow you to create components that can work over a variety of types rather than a single one, while maintaining full type safety.
1. Why Do We Need Generics?
Suppose you need a function that returns the first element of an array.
Without Generics
function getFirstElement(arr: any[]): any {
return arr[0];
}
const value = getFirstElement([1, 2, 3]);
// 'value' is typed as 'any', meaning we lose type safety for the rest of our code.Using any stops the compiler from tracking the output type.
With Generics
We introduce a type variable, typically named T, which captures the type passed to the function:
function getFirstElement<T>(arr: T[]): T {
return arr[0];
}
const num = getFirstElement([10, 20, 30]); // TypeScript infers 'num' is a 'number'
const str = getFirstElement(["a", "b"]); // TypeScript infers 'str' is a 'string'By using <T>, the function remembers the type of the elements and enforces it on the return value.
2. Generic Interfaces
You can also apply type variables to interfaces. This is useful for describing data containers or API response envelopes.
interface APIResponse<DataShape> {
statusCode: number;
data: DataShape;
}
interface User {
username: string;
}
const response: APIResponse<User> = {
statusCode: 200,
data: {
username: "Alice"
}
};3. Multiple Type Variables
You can define multiple type variables by separating them with commas:
function mergePairs<K, V>(key: K, value: V): [K, V] {
return [key, value];
}
const pair = mergePairs("age", 30); // Returns [string, number]4. Summary
- Generics enable code reuse by allowing components to accept types as parameters.
- Type parameters (like
<T>) capture user-provided types for functions and interfaces. - Using generics preserves type relationships between inputs and outputs, replacing the need for unsafe
anytypes.
Published on Last updated: