Một tệp TypeScript không thể chạy nguyên trạng, vì trình duyệt và các engine JavaScript không hiểu chú thích kiểu. Phải có thứ gì đó xóa kiểu đi trước. Thứ đó hoặc là trình biên dịch TypeScript (tsc), vốn cũng kiểm tra kiểu, hoặc là một công cụ nhanh hơn chỉ gỡ bỏ kiểu. Cách nhanh nhất để chạy code trên trang này là nút Chạy:
Đầu ra:
[x] Install TypeScript
[ ] Run a .ts file
Mọi khối code chạy được trong tài liệu này đều hoạt động giống nhau: code được TypeScript 7 kiểm tra kiểu với strict bật, và chỉ chạy khi không có lỗi kiểu. Với những thử nghiệm dài hơn, playground TypeScript là cùng trình soạn thảo đó trên một trang riêng. Phần còn lại của trang này nói về cách chạy tệp .ts trên máy của bạn.
Tổng quan các lựa chọn
| Lệnh | Kiểm tra kiểu | Cần bước build | Hỗ trợ enum, namespace, parameter property |
|---|---|---|---|
npx tsc rồi node dist/index.js | Có | Có | Có |
node index.ts (Node.js 22.18+, 23.6+) | Không | Không | Không |
npx tsx index.ts | Không | Không | Có |
npx ts-node index.ts | Có | Không | Có, nhưng không với TypeScript 7 |
deno run index.ts | Không (deno check thì có) | Không | Có |
bun index.ts | Không | Không | Có |
Cột khiến nhiều người bất ngờ là cột đầu tiên: phần lớn các lựa chọn nhanh đều chạy cả code có lỗi kiểu. Một dự án thường chạy code bằng một trong số đó và chạy riêng tsc --noEmit, trong trình soạn thảo và trong CI, để bắt lỗi.
Biên dịch bằng tsc, rồi chạy bằng Node
Đây là cách chạy được ở mọi nơi và kiểm tra mọi thứ. Khi dự án đã cài TypeScript và có tsconfig.json đặt "rootDir": "./src" và "outDir": "./dist":
npx tsc
node dist/index.js
tsc kiểm tra kiểu tất cả các tệp, rồi ghi các tệp .js vào dist. Với một tệp đơn lẻ không thuộc dự án nào, hãy truyền tên tệp. Khi đó nó dùng các tùy chọn mặc định và ghi index.js ngay cạnh index.ts:
npx tsc index.ts
node index.js
(Nếu thư mục có tsconfig.json, tsc sẽ từ chối tên tệp với error TS5112; hãy chạy npx tsc không kèm tên tệp, hoặc thêm --ignoreConfig.)
Mặc định tsc vẫn ghi ra JavaScript khi có lỗi kiểu, nên node có thể chạy một chương trình đã không qua được bước kiểm tra. Thêm "noEmitOnError": true vào cấu hình để ngăn điều đó, hoặc nối các lệnh trong một script để bước thứ hai chỉ chạy khi bước đầu thành công:
{
"scripts": {
"build": "tsc",
"start": "tsc && node dist/index.js"
}
}
Khi phát triển, npx tsc --watch biên dịch lại mỗi lần bạn lưu.
Chạy TypeScript trực tiếp bằng Node.js
Node.js hiện nay tự chạy được tệp .ts:
node index.ts
Node gỡ bỏ chú thích kiểu, thay chúng bằng khoảng trắng để số dòng trong stack trace vẫn khớp, rồi chạy phần còn lại. Tính năng này bật mặc định từ Node.js 23.6.0 và 22.18.0, không còn in cảnh báo từ 24.3.0 và 22.18.0, và được đánh dấu ổn định trong Node.js 24.12.0 và 25.2.0. Các bản phát hành cũ hơn có tính năng này (từ 22.6 đến 22.17, và từ 23.0 đến 23.5) cần cờ: node --experimental-strip-types index.ts.
Đi kèm là bốn quy tắc:
- Không kiểm tra kiểu. Một tệp có
const age: number = "forty"vẫn chạy và in raforty. - Chỉ cú pháp xóa được. Mọi thứ phải trở thành code JavaScript, thay vì biến mất, đều bị từ chối:
enum, khốinamespacecó code chạy lúc runtime, parameter property trong hàm khởi tạo nhưconstructor(private name: string), và aliasimport x = require(). Node dừng lại vớiSyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode. tsconfig.jsonbị bỏ qua. Các tùy chọn nhưpathshaytargetkhông có tác dụng.- Import cần tên tệp thật. Viết
import { add } from "./math.ts", có cả phần mở rộng, và đánh dấu import chỉ dùng cho kiểu bằngtype:import { add, type Pair } from "./math.ts". Không cótype, Node sẽ tìm một export lúc runtime tên làPairvà thất bại vớiSyntaxError: The requested module './math.ts' does not provide an export named 'Pair'.
Hai tùy chọn trình biên dịch khiến tsc áp dụng cùng các quy tắc đó, để trình soạn thảo cảnh báo bạn trước cả Node: "erasableSyntaxOnly": true báo error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled. khi gặp enum, và "verbatimModuleSyntax": true bắt buộc dùng từ khóa type cho import chỉ dùng cho kiểu. Để vẫn viết phần mở rộng .ts trong import mà vẫn biên dịch được bằng tsc, thêm "rewriteRelativeImportExtensions": true, tùy chọn này đổi ./math.ts thành ./math.js trong đầu ra.
Node.js 24 còn có --experimental-transform-types, cờ này sinh code cho enum và parameter property thay vì từ chối chúng. Nó in ra một ExperimentalWarning, và Node.js 26 đã bỏ cờ này, nên đừng xây dựng dựa trên nó.
Khối code này dùng hai tính năng mà node index.ts từ chối. Nó chạy được ở đây vì trình soạn thảo biên dịch nó bằng trình biên dịch TypeScript, vốn sinh JavaScript cho cả hai:
Phiên bản xóa được của cùng đoạn code dùng một đối tượng const và một trường bình thường, Node chạy được nguyên trạng:
tsx
tsx chạy một tệp TypeScript chỉ trong một bước, không cần cấu hình và không giới hạn cú pháp:
npm install --save-dev tsx
npx tsx index.ts
npx tsx watch index.ts # rerun on every change
Nó biến đổi code bằng esbuild, nên enum, namespace và parameter property đều chạy được, và import không có phần mở rộng được phân giải giống như trong một bundler. Giống type stripping của Node, nó không kiểm tra kiểu. Đây là lựa chọn phổ biến cho script, dev server và test trên các phiên bản Node.js ra đời trước type stripping, hoặc khi code dùng cú pháp mà Node từ chối.
ts-node
ts-node từng là cách tiêu chuẩn để chạy TypeScript trên Node.js trong nhiều năm, và vẫn là thứ mà nhiều bài hướng dẫn và dự án cũ dùng (npx ts-node index.ts, node -r ts-node/register). Mặc định nó kiểm tra kiểu, bằng API JavaScript của trình biên dịch TypeScript.
API đó chính là thứ TypeScript 7 không còn đi kèm: trình biên dịch của nó là một chương trình native, và package typescript 7 không cung cấp API trình biên dịch nào cho JavaScript. Khi đã cài TypeScript 7, ts-node crash trước khi chạy được bất cứ thứ gì:
TypeError: Cannot read properties of undefined (reading 'fileExists')
at readConfig (/project/node_modules/ts-node/dist/configuration.js:91:33)
Bản phát hành mới nhất của ts-node, 10.9.2, có từ tháng 12 năm 2023. Với code mới, hãy dùng tsx hoặc node index.ts. Một thiết lập cũ phụ thuộc vào ts-node vẫn chạy được nếu dự án giữ TypeScript 6 (npm install --save-dev typescript@6) và có tsconfig.json, kể cả chỉ là {} rỗng. Nếu không có tệp này, ts-node quay về các giá trị mặc định có sẵn, trong đó có cách phân giải module node10 mà TypeScript 6 đã ngừng hỗ trợ, và npx ts-node index.ts thoát ra mà không chạy tệp cũng không in lỗi nào.
Deno và Bun
Cả hai runtime đều coi TypeScript là một loại tệp chính thức:
deno run index.ts # runs without checking
deno check index.ts # type-checks, reports errors, runs nothing
bun index.ts # runs without checking
Cả hai đều không cần cài typescript hay có tsconfig.json, và đều hỗ trợ enum cùng các tính năng không xóa được khác. Deno đi kèm bản trình biên dịch TypeScript riêng cho deno check. Bun chỉ gỡ bỏ kiểu, nên trong một dự án Bun bạn vẫn cài typescript và chạy tsc --noEmit để tìm lỗi kiểu.
Chỉ tsc mới chặn chương trình có lỗi kiểu
Chỉ những cách chạy tsc trước mới từ chối chạy chương trình có lỗi kiểu. Trình soạn thảo trên trang này là một trong số đó, nên khối code này dừng lại ở trình biên dịch:
index.ts(6,21): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
Lưu thành tệp và chạy bằng node index.ts, npx tsx index.ts hoặc bun index.ts, cùng đoạn code đó vẫn chạy và in ra 12, vì 3 * "4" chuyển chuỗi thành số. Đó là lý do nên giữ tsc --noEmit trong quy trình ngay cả khi một công cụ nhanh hơn chạy code:
{
"scripts": {
"dev": "tsx watch src/index.ts",
"typecheck": "tsc --noEmit"
}
}
Bạn nên dùng cách nào?
- Đang học, hoặc thử nhanh: nút Chạy trên các trang này, hoặc playground.
- Một script hay công cụ nhỏ trên Node.js hiện tại:
node index.ts, vớierasableSyntaxOnlytrong cấu hình để trình soạn thảo đánh dấu mọi thứ Node sẽ từ chối. - Mọi dự án Node.js, mọi cú pháp:
tsxđể chạy,tsc --noEmitđể kiểm tra. - Một thư viện hay bất cứ thứ gì bạn phát hành:
tsc, vì nó còn ghi ra các tệp.d.tsmà người dùng của bạn cần. - Code front end: bundler hoặc framework của bạn (Vite, Next.js, Angular CLI) chạy TypeScript cho bạn; thêm
tsc --noEmitđể kiểm tra.
Câu hỏi thường gặp
Làm sao chạy một file TypeScript?
Cách truyền thống gồm hai bước: npx tsc biên dịch .ts thành .js, rồi node dist/index.js chạy kết quả. Từ Node.js 22.18 hoặc 23.6 trở lên, bạn cũng có thể chạy thẳng node index.ts, miễn là tệp chỉ dùng cú pháp kiểu có thể xóa đi được. npx tsx index.ts chạy mọi tệp TypeScript chỉ trong một bước.
Node.js có chạy trực tiếp TypeScript được không?
Có. Từ Node.js 23.6 và 22.18, node file.ts chạy được mà không cần cờ nào: Node bỏ các chú thích kiểu và chạy phần còn lại. Nó không kiểm tra kiểu, bỏ qua tsconfig.json, và từ chối cú pháp cần sinh code, như enum, namespace có code chạy lúc runtime và parameter property trong hàm khởi tạo.
ts-node có chạy được với TypeScript 7 không?
Không. ts-node gọi API JavaScript của trình biên dịch, thứ mà package typescript 7 không cung cấp, nên nó bị crash ngay khi khởi chạy (Cannot read properties of undefined (reading 'fileExists')). Bản phát hành cuối cùng của nó là 10.9.2 từ tháng 12 năm 2023. Hãy dùng tsx, type stripping có sẵn của Node, hoặc giữ ts-node cùng TypeScript 6.
tsx và ts-node khác nhau thế nào?
tsx chỉ xóa kiểu (bằng esbuild) rồi chạy kết quả, nên khởi động nhanh và không bao giờ báo lỗi kiểu. ts-node mặc định kiểm tra kiểu bằng trình biên dịch TypeScript, nên chậm hơn và phụ thuộc vào API JavaScript của trình biên dịch. Phần lớn dự án hiện nay dùng tsx hoặc node file.ts để chạy, kết hợp với tsc --noEmit để kiểm tra.
Có sandbox TypeScript online nào không?
Có. Các khối code trên những trang tài liệu này và playground TypeScript trên Coddy biên dịch code của bạn bằng TypeScript 7 rồi chạy nó, hiển thị lỗi của trình biên dịch hoặc đầu ra của chương trình. TypeScript Playground chính thức trên typescriptlang.org hiển thị JavaScript được sinh ra và các lỗi.