TypeScript Nâng Cao: Hiểu Rõ Bản Chất để Áp Dụng Đúng
Dành cho dev đã biết TypeScript cơ bản nhưng muốn hiểu sâu hơn về Generics, Decorators và Advanced Types – không chỉ biết cách dùng mà còn hiểu tại sao và khi nào nên dùng.
1. Generics: "Khuôn" Để Đúc Nhiều Kiểu Dữ Liệu
Bản chất:
Generics giống như một cái khuôn (template) cho phép bạn viết code một lần nhưng dùng được cho nhiều kiểu dữ liệu khác nhau, mà vẫn đảm bảo an toàn kiểu (type safety).
Khi nào dùng?
- Khi bạn muốn hàm/class của mình linh hoạt với nhiều kiểu dữ liệu.
- Nhưng không muốn hy sinh type checking của TypeScript.
Ví dụ thực tế:
// ❌ Không dùng Generics → phải viết nhiều hàm
function getString(value: string): string { return value; }
function getNumber(value: number): number { return value; } // ✅ Dùng Generics → 1 hàm làm việc cho mọi kiểu
function getValue<T>(value: T): T { return value;
} const name = getValue<string>("Alice"); // Kiểu string
const age = getValue<number>(25); // Kiểu number
Giải thích:
T
là biến kiểu (type variable), đại diện cho kiểu dữ liệu sẽ được truyền vào.- Khi gọi hàm, bạn chỉ định
T
làstring
,number
, hay bất kỳ kiểu nào.
Lưu ý quan trọng:
- Không phải lúc nào cũng cần Generics. Chỉ dùng khi bạn thực sự cần làm việc với nhiều kiểu.
- Đừng lạm dụng – nếu chỉ làm việc với 1 kiểu cụ thể, hãy dùng kiểu trực tiếp (
string
,number
,...).
2. Decorators: "Trang Trí" Code Để Thêm Tính Năng
Bản chất:
Decorator là hàm đặc biệt có thể "gắn" vào class, method, property để thay đổi hoặc thêm tính năng mà không cần sửa code gốc.
Khi nào dùng?
- Khi bạn muốn áp dụng tính năng chung (log, validate, cache,...) cho nhiều class/method.
- Tránh lặp code bằng cách tách cross-cutting concerns (logic chung) ra decorators.
Ví dụ thực tế:
// Decorator để log thời gian chạy của method
function logTime(target: any, methodName: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.time(methodName); const result = originalMethod.apply(this, args); console.timeEnd(methodName); return result; };
} class Calculator { @logTime // Gắn decorator vào method sum(a: number, b: number) { return a + b; }
} const calc = new Calculator();
calc.sum(1, 2); // Console sẽ hiện: "sum: 0.123ms"
Giải thích:
- Decorator
@logTime
bao bọc methodsum
để đo thời gian chạy. - Không cần sửa code của
sum
→ giữ nguyên logic chính. - Có thể tái sử dụng cho bất kỳ method nào khác.
Lưu ý quan trọng:
- Không phải magic! Decorator chỉ là hàm JavaScript chạy ở runtime.
- Cẩn thận performance nếu dùng quá nhiều decorator phức tạp.
3. Advanced Types: Kiểu Dữ Liệu "Thông Minh" Hơn
Bản chất:
TypeScript có nhiều kiểu nâng cao giúp bạn mô tả chính xác hơn cấu trúc dữ liệu, giảm bug và tăng khả năng tự động hoàn thành code.
Khi nào dùng?
- Khi bạn muốn kiểm soát chặt chẽ kiểu dữ liệu đầu vào/đầu ra.
- Khi làm việc với dữ liệu phức tạp (API response, Redux state,...).
Ví dụ thực tế:
Union Types (|
): "Hoặc cái này, hoặc cái kia"
type Status = "success" | "error" | "loading"; function handleStatus(status: Status) { if (status === "success") { console.log("Thành công!"); } else if (status === "error") { console.log("Lỗi!"); }
} handleStatus("success"); // OK
handleStatus("pending"); // ❌ Lỗi: "pending" không nằm trong kiểu Status
Type Guards: Kiểm tra kiểu tại runtime
interface User { name: string; age: number;
} function isUser(obj: any): obj is User { return obj && typeof obj.name === "string" && typeof obj.age === "number";
} const data = JSON.parse('{"name":"Alice","age":25}'); if (isUser(data)) { console.log(data.name); // TypeScript "biết" data là User
}
Lưu ý quan trọng:
- Đừng làm phức tạp quá. Nếu kiểu quá phức tạp, hãy cân nhắc refactor code.
- Dùng
unknown
thay choany
khi làm việc với dữ liệu động để an toàn hơn.
Kết Luận: Khi Nào Dùng Gì?
Tính năng | Khi nào dùng? | Ví dụ thực tế |
---|---|---|
Generics | Code làm việc với nhiều kiểu dữ liệu | API service, hàm utility |
Decorators | Thêm tính năng không sửa code gốc | Logging, validation, caching |
Advanced Types | Kiểm soát kiểu dữ liệu phức tạp | API response, Redux state |
🤑 Vậy là hôm nay ae ta đã cùng nhau tìm hiểu một vài khái niệm nâng cao của Typescript. Ngoài những thứ trên thì ae sử dụng gì trong dự án của mình.
Hãy comment bên dưới nhé. Bye bye~~