Typescript Generics Made Easy

I'm Yogesh Kanwade, a final year Computer Engineering student with a deep passion for software development. I am a continuous learner, with hardworking and goal-driven mindset and strong leadership capabilities. I am actively exploring the vast possibilities of Web Development along with AWS and DevOps, fascinated by their impact on scalable and efficient web solutions.
Problem with ‘any’
function identity(arg: any): any {
return arg;
}
function identity(arg: any) {
return arg;
}
const result = identity(1);
Above examples of an identity function are essentially the same. With or without explicit return, typescript infers the type of result as any. Even in the case with no explicit return since arg is any.
Typescript Generics
Typescript generics allow us to define generic function by adding a type parameter in angle brackets before the function's parameters. Here we can use a type variable T , which is a placeholder type that adapts to whatever we pass in. Thus a generic function is a function that can work with any data type.
If we use generics, TypeScript can infer the return type based on the argument.
function identity<T>(arg: T): T {
return arg;
}
const result = identity<string>('hello');
// result is of type string
const result = identity(3);
// typecript inferes result is of type number as argument passed is a number.
Example:
function mergeObjects<T extends object, U extends object>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
TandUare generic types extendingobject, ensuring both arguments are objects.The return type is
T & U, meaning it combines both object types into one.
const user = { name: "Alice", age: 25 };
const details = { job: "Engineer", active: true };
const merged = mergeObjects(user, details);
// Type of `merged` is inferred as:
// { name: string; age: number; } & { job: string; active: boolean }
Generic Utility Types
TypeScript provides built-in utility types based on generics:
Pick<T, K>
Selects the specified keys (
K) from the given type (T).interface User { id: number; name: string; age: number; } type UserNameOnly = Pick<User, "name">; const user: UserNameOnly = { name: "Alice" };Omit<T, K>
Removes the specified keys (
K) from the given type (T).Example
interface User { id: number; name: string; email: string; password: string; } // Omit 'password' from User type type PublicUser = Omit<User, 'password'>; const user: PublicUser = { id: 1, name: 'Alice', email: 'alice@example.com', };Use Case: Hiding sensitive information like passwords in API responses.
Required<T>
Converts all optional properties in
Tto mandatory.Example
interface UserSettings { theme?: string; notifications?: boolean; } // Make all properties required type StrictSettings = Required<UserSettings>; const settings: StrictSettings = { theme: 'dark', notifications: true, // If we omit any property, TypeScript will give an error };Use Case: Ensuring that an object always has all properties before using it.
Partial<T>
Makes all properties optional.
tsCopyEdittype PartialUser = Partial<User>; const user: PartialUser = { name: "Bob" };Readonly<T>
Prevents modification of properties.
tsCopyEditconst user: Readonly<User> = { id: 1, name: "Alice", age: 25 }; // user.name = "Bob"; ❌ Error: Cannot assign to 'name' because it is a read-only property.




