5 phút khởi đầu nhanh: Chuyển từ .js sang .ts
JavaScript cực kỳ linh hoạt, nhưng sự tự do đó thường đi kèm với một cái giá khá đắt. Chỉ một lỗi đánh máy nhỏ trong tên thuộc tính cũng có thể khiến toàn bộ ứng dụng của bạn bị crash với lỗi kinh điển TypeError: cannot read property 'x' of undefined. Theo khảo sát State of JS năm 2023, hơn 70% lập trình viên hiện đang sử dụng TypeScript để giải quyết chính xác vấn đề này. Nó thêm một lớp static typing (kiểu tĩnh) đóng vai trò như một mạng lưới an toàn cho logic của bạn.
Tôi vẫn nhớ tuần đầu tiên mình chuyển sang dùng nó. Tôi đã dành một nửa thời gian để “vật lộn” với các lỗi compiler và cảm thấy rất nản lòng. Nhưng rồi tôi nhận ra một điều: mỗi lỗi mà compiler đưa ra thực chất là một bug mà tôi chưa phát hiện được. Thà sửa lỗi ngay trong editor còn hơn là nhận cảnh báo lúc 2 giờ sáng vì server production bị sập.
Bắt đầu rất đơn giản nếu bạn đã cài Node.js. Hãy chạy lệnh này trong terminal để cài đặt compiler:
npm install -g typescript
Tạo một file có tên app.ts. Phần mở rộng .ts cho cả thế giới biết rằng đây không còn là JavaScript thuần túy nữa. Hãy dán đoạn mã này vào:
let username: string = "itfromzero";
let age: number = 25;
function greet(name: string): string {
return `Xin chào, ${name}`;
}
console.log(greet(username));
Để chuyển mã này thành code có thể chạy trên trình duyệt, hãy chạy compiler:
tsc app.ts
Công cụ sẽ tạo ra một file app.js ngay lập tức. Nếu bạn cố gắng truyền một con số vào hàm greet đó, TypeScript sẽ gạch chân đỏ dòng đó ngay cả trước khi bạn lưu file. Vòng lặp phản hồi tức thì này chính là lý do tại sao các đội ngũ hiện đại từ chối làm việc mà không có nó.
Những điều cốt lõi: Cách TypeScript “tư duy”
Static typing không chỉ đơn thuần là thêm các ký tự thừa thãi vào file của bạn. Nó tạo ra một bản hợp đồng chính thức giữa các phần khác nhau trong phần mềm. Trong kinh nghiệm của tôi, sự thay đổi trong tư duy này quan trọng hơn việc học cú pháp thực tế.
Type Inference: Người trợ giúp thầm lặng
Không phải lúc nào bạn cũng cần khai báo rõ ràng. TypeScript có khả năng quan sát đáng ngạc nhiên. Nếu bạn viết let count = 10;, engine sẽ tự động gán cho nó kiểu number. Bạn chỉ cần định nghĩa kiểu thủ công khi logic trở nên phức tạp hoặc khi khởi tạo các biến rỗng.
- string: Cho tất cả dữ liệu dạng văn bản.
- number: Xử lý cả số nguyên và số thập phân.
- boolean: Các giá trị đóng/mở true hoặc false đơn giản.
- Array: Viết là
number[]hoặcArray<string>.
Interfaces: Định nghĩa cấu trúc dữ liệu
Interface là thành phần thiết yếu của code TypeScript sạch. Chúng cho phép bạn định nghĩa chính xác một object trông như thế nào. Hãy ngừng truyền các object “bí ẩn” và bắt đầu định nghĩa các cấu trúc rõ ràng.
interface User {
id: number;
username: string;
email: string;
isAdmin?: boolean; // Dấu '?' nghĩa là thuộc tính này không bắt buộc
}
const newUser: User = {
id: 1,
username: "dev_pro",
email: "[email protected]"
};
Nếu bạn vô tình gõ user.mail thay vì user.email, editor sẽ phát hiện ra ngay. Điều này loại bỏ những bug khó chịu khi frontend mong đợi một tên trường nhưng API lại trả về một tên khác.
Sự linh hoạt không đi kèm với hỗn loạn
Một khi bạn đã nắm vững những điều cơ bản, bạn sẽ gặp phải những tình huống mà dữ liệu không hoàn toàn dễ đoán. TypeScript xử lý việc này một cách khéo léo mà không làm mất đi tính an toàn.
Union Types và Type Guards
Dữ liệu thực tế thường rất lộn xộn. Một ID có thể là số 101 từ một database cũ hoặc một chuỗi "uuid-abcd" từ một dịch vụ mới hơn. Union types cho phép bạn xử lý cả hai trường hợp.
function printId(id: number | string) {
if (typeof id === "string") {
// TypeScript biết 'id' ở đây là một chuỗi
console.log("ID là một chuỗi: " + id.toUpperCase());
} else {
// Ở đây, 'id' chắc chắn là một con số
console.log("ID là một con số: " + id.toFixed(2));
}
}
printId(101); // Hợp lệ
printId("abc-123"); // Cũng hợp lệ
Việc kiểm tra if ở trên được gọi là “Type Guard”. Nó cho phép compiler thu hẹp kiểu dữ liệu để bạn có thể sử dụng các phương thức đặc thù một cách an toàn như toUpperCase().
Generics: Logic có thể tái sử dụng
Generics giống như các biến dành cho kiểu dữ liệu của bạn. Chúng cho phép bạn viết một hàm một lần và sử dụng nó cho string, number hoặc các object tùy chỉnh trong khi vẫn giữ mọi thứ an toàn về kiểu (type-safe).
function wrapInArray<T>(item: T): T[] {
return [item];
}
const numberArray = wrapInArray(5); // Kết quả là number[]
const stringArray = wrapInArray("TS"); // Kết quả là string[]
Ký hiệu <T> là một trình giữ chỗ. Khi bạn truyền vào một số, T sẽ trở thành number. Điều này giúp bạn tránh sử dụng kiểu any, vốn là quy tắc số một để viết TypeScript tốt.
Những bài học đắt giá từ thực tế production
Chuyển đổi một dự án lớn sang TypeScript đòi hỏi nhiều hơn là chỉ biết cú pháp. Dưới đây là ba chiến lược tôi thường dùng để giữ cho codebase luôn khỏe mạnh.
1. Tránh bẫy ‘any’
Sử dụng any khi đang vội là một cám dỗ lớn. Đừng làm vậy. Việc dùng any về cơ bản là tắt TypeScript và đưa bạn quay lại thời kỳ “miền Tây hoang dã” của JavaScript. Nếu bạn thực sự chưa biết kiểu dữ liệu, hãy dùng unknown. Nó buộc bạn phải kiểm tra kiểu trước khi sử dụng biến, giúp ứng dụng của bạn an toàn hơn.
2. Bật Strict Mode sớm
Mọi dự án đều cần một file tsconfig.json. Hãy tạo nó bằng cách chạy tsc --init. Bên trong, hãy đảm bảo "strict": true đã được bật. Mặc dù nó khiến compiler “phàn nàn” nhiều hơn, nhưng nó ngăn chặn hầu hết các lỗi null pointer phổ biến thường gặp trong các ứng dụng JavaScript.
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"strict": true,
"skipLibCheck": true
}
}
3. Sử dụng Type Alias để code rõ ràng hơn
Nếu bạn thấy mình viết đi viết lại string | number | undefined, bạn đang tạo ra một cơn ác mộng về bảo trì. Thay vào đó, hãy tạo một Type Alias. Nó giúp các chữ ký hàm (function signatures) của bạn dễ đọc hơn nhiều khi liếc qua.
type UserID = string | number;
function fetchUser(id: UserID) {
// Sạch sẽ hơn nhiều!
}
Chuyển đổi một dự án lớn sang TypeScript có thể tạo cảm giác tốn thêm công sức lúc đầu, nhưng nó mang lại lợi ích to lớn trong quá trình refactoring. Khi bạn thay đổi một tên thuộc tính duy nhất và compiler cho bạn biết chính xác 15 file nào vừa bị lỗi, bạn sẽ nhận ra đó là “người đồng đội” tốt nhất mà bạn từng có.

