Generics In Typescript

 Generics in TypeScript are a powerful feature that allows you to write flexible and reusable code by parameterizing types. Generics enable you to define functions, classes, and interfaces that work with a variety of data types, providing type safety and avoiding code duplication. Let's delve into the details of generics in TypeScript:

1. Generic Functions:

Multiple Type Parameters:

function merge<T, U>(obj1: T, obj2: U): T & U {
    return { ...obj1, ...obj2 };
}

let mergedObj = merge({ name: "John" }, { age: 30 });
// mergedObj has type { name: string, age: number }

Generic Functions with Constraints:

interface Lengthwise {
    length: number;
}

function getLength<T extends Lengthwise>(obj: T): number {
    return obj.length;
}

let strLength = getLength("Hello"); // strLength is 5

2. Generic Classes:

Using Generics in Class Methods:

class Stack<T> {
    private items: T[] = [];

    push(item: T): void {
        this.items.push(item);
    }

    pop(): T | undefined {
        return this.items.pop();
    }
}

let numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
let poppedItem = numberStack.pop();
// poppedItem is of type number | undefined

3. Using Generic Types with Constraints:

Extending Interfaces:

interface Printable {
    print(): void;
}

function printObject<T extends Printable>(obj: T): void {
    obj.print();
}

class Person implements Printable {
    print(): void {
        console.log("Printing person...");
    }
}

let john = new Person();
printObject(john); // Prints "Printing person..."

4. Using Generics with Arrays:

Array Operations:

function reverseArray<T>(arr: T[]): T[] {
    return arr.reverse();
}

let reversedNames = reverseArray<string>(["John", "Jane"]);
// reversedNames is of type string[]

Mapping Arrays:

function mapArray<T, U>(arr: T[], fn: (item: T) => U): U[] {
    return arr.map(fn);
}

let numbers = [1, 2, 3, 4];
let doubledNumbers = mapArray(numbers, (num) => num * 2);
// doubledNumbers is of type number[]

5. Using Generic Constraints with keyof:

Accessing Object Properties:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

let person = { name: "John", age: 30 };
let name = getProperty(person, "name"); // name is of type string
let age = getProperty(person, "age"); // age is of type number

6. Generic Utility Types:

Partial:

interface Todo {
    title: string;
    description: string;
}

function updateTodo(todo: Todo, updates: Partial<Todo>): Todo {
    return { ...todo, ...updates };
}

let todo: Todo = { title: "Study", description: "Learn TypeScript" };
let updatedTodo = updateTodo(todo, { description: "Master TypeScript" });
// updatedTodo has type Todo

Pick:

interface User {
    id: number;
    name: string;
    email: string;
}

type UserWithoutEmail = Pick<User, "id" | "name">;
// UserWithoutEmail is { id: number, name: string }

Generics in TypeScript offer a powerful way to write flexible and reusable code while maintaining type safety. By using generics effectively, you can create versatile components and functions that work with various data types and structures. Experiment with generics in your TypeScript projects to gain a deeper understanding of their capabilities.

Post a Comment

0 Comments