Bỏ qua điều hướng

TypeScript là gì? Ngôn ngữ giúp JavaScript an toàn hơn

TypeScript là lớp kiểm tra kiểu tĩnh phủ lên JavaScript, chặn lỗi ngay lúc biên dịch; bản 7.0 viết bằng Go biên dịch nhanh gấp khoảng 10 lần.

Tuan Tran Van
10 phút đọc
Mục lục (10 phần)
  1. TypeScript là gì?
  2. Vì sao JavaScript cần thêm một lớp kiểu tĩnh?
  3. Hệ thống kiểu: suy luận, interface và kiểu cấu trúc
  4. Từ TypeScript sang JavaScript: trình biên dịch tsc
  5. Chế độ strict: chọn mức kiểm tra phù hợp với dự án
  6. Chạy TypeScript không cần bước build: type stripping trong Node.js
  7. TypeScript 7 và trình biên dịch mới viết bằng Go
  8. Khi nào nên dùng TypeScript, khi nào JavaScript là đủ?
  9. Nên bắt đầu học TypeScript từ đâu?
  10. Tài liệu tham khảo

TypeScript là một "typed superset" của JavaScript, cung cấp hệ thống kiểm tra kiểu tĩnh (static type-checking) để phát hiện lỗi ngay trong quá trình viết code thay vì đợi ứng dụng sập lúc đang chạy.

Trả lời thẳng câu hỏi TypeScript là gì: đây là JavaScript cộng thêm một lớp kiểm tra kiểu đặt bên trên — cùng cú pháp, cùng cách chạy, chỉ khác ở chỗ lỗi bị chặn sớm hơn nhiều.

Nếu bạn không muốn thức đêm để mò xem tại sao một biến undefined làm sập server, hãy dùng hệ thống kiểu của TypeScript. Nó giữ nguyên mọi tính năng của JavaScript nhưng thêm một lớp bảo vệ giúp mã nguồn ổn định và dễ bảo trì hơn.

TypeScript là lớp kiểm tra kiểu phủ lên JavaScript, hình ảnh chủ đề của bài viết

TypeScript là gì?

Về bản chất, TypeScript là một "Typed Superset" của JavaScript. Điều này nghĩa là mọi mã JavaScript bạn viết đều là mã TypeScript hợp lệ, nhưng điều ngược lại thì không đúng. TypeScript không thay đổi cách JavaScript vận hành; nó chỉ đắp thêm một hệ thống kiểu phía trên để quản lý dữ liệu chặt chẽ hơn. Bạn có thể coi JavaScript là lõi, và TypeScript là lớp vỏ kiểm soát logic bao bọc xung quanh.

Mọi mã JavaScript đều nằm gọn trong TypeScript, và toàn bộ phần kiểu bị xoá sạch sau khi biên dịch

Câu chuyện của TypeScript bắt đầu từ lúc JavaScript chuyển mình: từ một ngôn ngữ script đơn giản cho trình duyệt thành công cụ xử lý ứng dụng hàng triệu dòng code. Ban đầu, JavaScript chỉ dùng cho các đoạn mã ngắn. Khi web tiến hóa thành các ứng dụng phức tạp, những "quirks" (điểm kỳ quặc) của JS trở thành gánh nặng. TypeScript ra đời để biến JavaScript thành một công cụ lập trình chuyên nghiệp, đủ sức gánh vác các dự án quy mô doanh nghiệp.

Một khái niệm bạn cần nắm vững là "Erased Types". Sau khi bạn chạy trình biên dịch, toàn bộ hệ thống kiểu sẽ bị xóa bỏ hoàn toàn. Kết quả cuối cùng là file JavaScript thuần túy, sạch sẽ để chạy trên trình duyệt hoặc Node.js. Hệ thống kiểu chỉ tồn tại để hỗ trợ bạn lúc lập trình; nó hoàn toàn không tác động đến hành vi hay làm chậm ứng dụng lúc chạy (runtime).

Vì sao JavaScript cần thêm một lớp kiểu tĩnh?

JavaScript có rất nhiều hành vi gây ức chế. Phép so sánh bằng == thực hiện ép kiểu tự động (coercion) khiến "" == 0 trả về true. Hoặc khi bạn truy cập một thuộc tính không tồn tại, JS trả về undefined thay vì báo lỗi. Nếu bạn mang giá trị đó đi tính toán, kết quả sẽ là NaN và lỗi sẽ lan truyền âm thầm qua hàng chục hàm khác trước khi làm sập hệ thống.

JavaScript để lỗi lọt tới lúc chạy, còn TypeScript chặn lỗi ngay tại bước biên dịch

Hãy nhìn vào con số thực tế. Một startup fintech từng mất 18.000 USD doanh thu chỉ vì một hàm JavaScript hỏng mà không báo lỗi: một chuỗi ngày tháng (date string) bị truyền vào nơi lẽ ra phải là một con số timestamp, và giao dịch bị xử lý sai. Với TypeScript, lỗi này bị chặn ngay từ bước biên dịch (compile-time). Lập trình viên sẽ thấy dấu gạch đỏ ngay lập tức, và đoạn code lỗi đó không bao giờ được đẩy lên máy chủ.

Sự khác biệt cốt lõi nằm ở kiểu động (Dynamic Typing, JS) và kiểu tĩnh (Static Typing, TS). Trong JS, một biến có thể là chuỗi ở dòng 1 nhưng thành con số ở dòng 10. TS biến các rủi ro runtime thành lỗi compile-time. Trình kiểm tra kiểu buộc bạn phải minh bạch về dữ liệu trước khi cho phép mã nguồn chạy.

Hệ thống kiểu: suy luận, interface và kiểu cấu trúc

Bạn không cần phải khai báo kiểu cho mọi biến vì TypeScript có cơ chế "Type Inference" (suy luận kiểu). Nếu bạn viết let msg = "hello", nó tự hiểu msgstring. Bạn chỉ cần thêm khai báo kiểu ở những chỗ phức tạp mà trình biên dịch không thể tự suy ra.

Ba trụ của hệ thống kiểu TypeScript: suy luận kiểu, interface mô tả cấu trúc và kiểu cấu trúc so khớp theo hình dạng

Để mô tả cấu trúc của một object, bạn dùng interface hoặc type. Đây là cách bạn đặt ra quy định cho dữ liệu:

typescript
interface User {
  name: string;
  id: number;
}
 
const user: User = {
  name: "Hayes",
  id: 0,
};

TypeScript sử dụng hệ thống kiểu cấu trúc (Structural Type System), hay còn gọi là "Duck Typing". Nghĩa là nếu hai đối tượng có cấu trúc giống nhau (cùng tên thuộc tính và kiểu dữ liệu), chúng được coi là cùng một kiểu, bất kể tên gọi khác nhau. Ngoài ra, bạn có thể tạo các kiểu linh hoạt bằng Unions (|) để cho phép biến nhận nhiều loại dữ liệu, hoặc dùng Generics (<T>) để viết code tái sử dụng được cho nhiều kiểu dữ liệu khác nhau mà vẫn đảm bảo an toàn.

Từ TypeScript sang JavaScript: trình biên dịch tsc

Vì trình duyệt không đọc được file .ts, bạn cần tsc (TypeScript Compiler) để chuyển đổi. Một tính năng quan trọng ở đây là "Downleveling". tsc có thể hạ cấp mã ES6+ (hiện đại) xuống ES5 (cũ) dựa trên tùy chọn target để ứng dụng chạy được trên các trình duyệt lạc hậu mà không cần bạn phải viết code kiểu cũ.

Quy trình biên dịch: file .ts đi qua tsc, bị xoá phần kiểu và hạ cấp cú pháp, thành file .js chạy được

Mọi dự án đều bắt đầu với file tsconfig.json. Đây là file config tối thiểu để quản lý cách biên dịch. Ví dụ:

json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "strict": true,
    "outDir": "./dist",
    "noEmitOnError": true
  }
}

Lưu ý tính chất "Emitting with Errors": theo mặc định, TypeScript vẫn tạo ra file JS ngay cả khi có lỗi kiểu, để không cản trở quá trình chuyển đổi từ JS cũ. Tuy nhiên, bạn nên bật noEmitOnError để quy trình build chỉ thành công khi mã nguồn sạch lỗi hoàn toàn.

Chế độ strict: chọn mức kiểm tra phù hợp với dự án

Khi làm dự án mới, hãy luôn bật strict: true. Đây là chế độ kỷ luật nhất để đảm bảo an toàn mã nguồn. Trong đó có hai flag bạn buộc phải biết:

  1. noImplicitAny: cấm việc biến bị ép về kiểu any ngầm định. Kiểu any là "hố đen" triệt tiêu mọi khả năng bảo vệ của TypeScript.
  2. strictNullChecks: kiểm soát lỗi "tỷ đô" (billion dollar mistake). Bạn sẽ buộc phải xử lý trường hợp dữ liệu bị null hoặc undefined trước khi truy cập thuộc tính của nó.

Nếu đang chuyển đổi từ một dự án JS khổng lồ, bạn có thể tắt strict và tăng dần độ khắt khe theo từng giai đoạn để tránh bị "ngộp" vì hàng nghìn cảnh báo cùng lúc.

Chạy TypeScript không cần bước build: type stripping trong Node.js

Node.js đã hỗ trợ chạy trực tiếp file .ts thông qua cơ chế "Type stripping": thử nghiệm từ v22.7.0, bật mặc định từ v23.6.0 và v22.18.0, rồi chính thức ổn định từ v25.2.0 và v24.12.0. Node sẽ xóa bỏ cú pháp kiểu và thay bằng khoảng trắng để engine V8 có thể thực thi như JS thuần túy.

Cần phân biệt rõ hai cấp độ:

  • Hỗ trợ đầy đủ (full support): dùng công cụ bên thứ ba như tsx để hỗ trợ toàn bộ tính năng, bao gồm cả các chuyển đổi phức tạp.
  • Hỗ trợ tối giản (lightweight, có sẵn trong Node): Node chỉ đơn giản là "dọn dẹp" file để chạy. Cơ chế này không kiểm tra kiểu, bạn phải tự chịu trách nhiệm về logic kiểu của mình. Nó cũng không hỗ trợ Enum, namespace có code runtime, hoặc parameter properties.

Cơ chế này bỏ qua bước tạo source map, giúp script chạy nhanh hơn trong môi trường phát triển.

TypeScript 7 và trình biên dịch mới viết bằng Go

TypeScript 7 là một bước ngoặt lớn khi đội ngũ phát triển đập đi xây lại trình biên dịch bằng ngôn ngữ Go. Thay vì chạy trên runtime của JS (single-thread), trình biên dịch mới tận dụng khả năng đa luồng (shared memory multithreading) của Go để xử lý song song.

TypeScript 7 viết lại trình biên dịch bằng Go, rút ngắn thời gian build khoảng 8–12 lần

Hiệu năng thực tế tăng rõ rệt:

  • Tốc độ build nhanh hơn 8–12 lần. Dự án VS Code giảm thời gian build từ 125,7 giây xuống còn 10,6 giây.
  • Trải nghiệm trong editor nhanh hơn 13 lần: từ 17,5 giây xuống dưới 1,3 giây để hiển thị lỗi đầu tiên.
  • Tiết kiệm bộ nhớ từ 6% đến 26% tùy quy mô dự án.

Bạn có thể tận dụng tối đa CPU qua các flag mới như --checkers (song song hóa việc kiểm tra kiểu) và --builders. Chế độ --watch cũng được xây dựng lại dựa trên Parcel watcher, mang lại phản hồi gần như tức thì khi bạn thay đổi code.

Khi nào nên dùng TypeScript, khi nào JavaScript là đủ?

Lập trình viên hiện dành trung bình 77% thời gian viết code cho TypeScript, và 86% mã JavaScript chạy trên trình duyệt đều đi qua một bước build. TypeScript giờ là chuẩn chung của ngành.

Khi nào nên chọn TypeScript và khi nào JavaScript là đủ

  • Dùng TypeScript: cho dự án thực tế, làm việc nhóm, hoặc ứng dụng doanh nghiệp. Khả năng refactor code an toàn mà không sợ làm hỏng logic ở những file không liên quan là lợi ích lớn nhất TS mang lại.
  • Dùng JavaScript: cho các bản prototype vứt đi sau một ngày, script đơn giản, hoặc khi bạn cần thử nghiệm ý tưởng cực nhanh mà không muốn "đấu tranh" với hệ thống kiểu.

Tương lai "build-less" đang đến cùng type stripping, nhưng TypeScript vẫn là lớp bảo vệ mà hệ sinh thái JavaScript dựa vào.

Nên bắt đầu học TypeScript từ đâu?

Bạn không thể học TypeScript nếu không vững JavaScript, vì TS thực chất là JS cộng thêm hệ thống kiểm tra kiểu. Đừng cố đi tắt đón đầu.

Lộ trình cụ thể: dùng TypeScript Playground để thử nghiệm cú pháp trực tuyến, chạy npm install -g typescript để có trình biên dịch trên máy, rồi dùng tsc --init trong thư mục dự án và bắt đầu chuyển đổi các hàm JS nhỏ sang TS.

Tài liệu tham khảo

Chia sẻ bài viết

X / TwitterFacebookLinkedIn