Giới thiệu

TypeScript phát hiện lỗi tại thời gian biên dịch. Generic cho phép viết hàm, lớp tái sử dụng mà vẫn giữ kiểu an toàn.

Generic cơ bản

Định nghĩa

Generic khai báo trong dấu <>. Cú pháp: function identity(arg: T): T { return arg; }. Khi gọi, TypeScript suy ra kiểu hoặc truyền trực tiếp.

Ví dụ thực tế

Lấy giá trị một trường từ mảng đối tượng mà không mất kiểu.

function pluck<T, K extends keyof T>(arr: T[], key: K): T[K][] {
    return arr.map(item => item[key]);
}

Sử dụng: const ids = pluck(users, 'id'); // ids: number[] nếu users có trường id kiểu number.

Constraint (Ràng buộc)

Ràng buộc giới hạn kiểu generic để truy cập thuộc tính an toàn.

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

Gọi: getProperty(person, 'name'); // trả về string nếu person.name là string.

Utility Types

Partial

Biến tất cả thuộc tính thành tùy chọn.

type UserUpdate = Partial<User>;

Pick

Lấy một subset các thuộc tính.

type UserName = Pick<User, 'firstName' | 'lastName'>>;

Omit

Bỏ một số thuộc tính.

type UserWithoutPassword = Omit<User, 'password'>>;

Generic trong lớp

Lớp có thể nhận kiểu để tái sử dụng cho nhiều mô hình dữ liệu.

class Repository<T> {
    private items: T[] = [];
    add(item: T): void { this.items.push(item); }
    findAll(): T[] { return this.items; }
}

Sử dụng: const userRepo = new Repository<User>();

Kết hợp Generic với Conditional Types

Cho phép tạo kiểu dựa trên điều kiện.

type IsString = T extends string ? true : false;

Kiểm tra: type Test = IsString<number>; // false

Kết luận

Generic giảm lỗi runtime, tăng tính tái sử dụng, giúp code sạch hơn. Tham khảo khóa học "Lập trình TypeScript từ cơ bản đến nâng cao" tại đây.