Generics, reminds me to early days of studying typescript, when i see those T, U, V characters inside < brackets > that scared the hell out of me and i try to avoid them.
once i understand them, they are actually not that scary, they are powerful.
I collected examples that will help you quickly understand why, and how to use generics, without have to read through the complex documentation and confusing explanations. 😭
What are Generics?
Generics let you pass a type as a parameter to functions, interfaces, or classes.
Think of it as a function parameter, but for types.
function doSomething<T>(input: T): T {
return input;
}
Here, T is a type placeholder. When you use the function, T gets replaced by the actual type you pass.
T is just convention, you can actually name it anything you like,
function doSomething<TTypeBeingPassedHere>(input: TTypeBeingPassedHere): TTypeBeingPassedHere {
return input;
}
To give distinct identifier, commonly its starts with T followed by the name, here is another example
function doSomething<TInput>(inputOne: TInput): TInput {
// ... some logic here
return input;
}
doSomething<number>(1) // returns number
doSomething<string>("1") // returns string
This code defines the function must always return TInput
, and it passed by the of the caller,
in this case TInput
passed as number
hence it will return number
🧐 Why Use Generics?
Avoid using any (which removes type safety)
Avoid code duplication
Write reusable and type-safe utilities
to easier understand how generic works and its benefits, take a look of more examples below.
Common use case scenarios
Reusing Logic Without Losing Types
Scenario: You want to write a utility function that works with any type but still keeps the original type intact.
function wrapInArray<T>(value: T): T[] {
return [value];
}
const numberArray = wrapInArray(123); // number[]
const stringArray = wrapInArray('hello'); // string[]
🧠 Why use generics?
- If you used any, you’d lose type safety.
- If you hardcoded string, you couldn’t reuse it for number.
Handling API Responses
Scenario: You fetch data from different endpoints. All responses follow the same format: data + success. But the data can vary.
interface ApiResponse<T> {
data: T;
success: boolean;
}
const userResponse: ApiResponse<{ id: number; name: string }> = {
data: { id: 1, name: 'Alice' },
success: true,
};
const postsResponse: ApiResponse<string[]> = {
data: ['post 1', 'post 2'],
success: true,
};
🧠 Why use generics?
- You avoid duplicating the structure. ApiResponse can be re-used for different response shape.
- You get full type safety no matter what data is.
Creating Flexible List Utilities
Scenario: You want a function like getFirstItem, and you want it to work for any array type.
function getFirstItem<T>(list: T[]): T | undefined {
return list[0];
}
const firstName = getFirstItem(['Rick', 'Morty']); // string
const firstNumber = getFirstItem([10, 20, 30]); // number
🧠 Why use generics?
Extending Built-in Types Safely
Scenario: You want to write a function that only accepts objects that have a length, like strings or arrays — not numbers or booleans.
function logLength<T extends { length: number }>(value: T): void {
console.log(value.length);
}
logLength('hello'); // valid
logLength([1, 2, 3]); // valid
logLength(100); // ❌ Error: number doesn't have length
🧠 Why use generics with extends?
- Combined with use of Extends, you can selectively accepts types of Generics you allow, in this case logLength only accepts anything that compatible with
{ length: number}
- You define a flexible type that still enforces structure.
React Hook That Works with Any Type
Scenario: You want a useLocalStorage hook that works with any type of value — string, number, object, etc.
function useLocalStorage<T>(key: string, initialValue: T): [T, (val: T) => void] {
const [value, setValue] = React.useState<T>(() => {
const json = localStorage.getItem(key);
return json ? JSON.parse(json) : initialValue;
});
React.useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
🧠 Why use generics?
- So this hook works with boolean, string, { id: number }, or anything else, with full autocomplete and safety.
Generic Class for Storing Any Type
Scenario: You want a class that stores data of any type.
class Store<T> {
private items: T[] = [];
add(item: T) {
this.items.push(item);
}
getAll(): T[] {
return this.items;
}
}
const userStore = new Store<{ id: number; name: string }>();
userStore.add({ id: 1, name: 'Alice' });
const numberStore = new Store<number>();
numberStore.add(10);
🧠 Why use generics?
- One class works for both objects, strings, and numbers - without rewriting the logic.
official reference https://www.typescriptlang.org/docs/handbook/2/generics.html
Top comments (0)