Bài 10 · Vận dụng · 20 phút
tsconfig, strict & .d.ts
Biên soạn bởi Nguyễn Anh Tuấn
Những cấu hình tsc đáng quan tâm: nhóm strict, target / module / moduleResolution; tệp khai báo kiểu (.d.ts) và DefinitelyTyped (@types) để gắn kiểu cho thư viện JS chưa có kiểu; import type. Phần đời thực của một dự án TypeScript.
Một dự án TypeScript được điều khiển bởi tsconfig.json ở thư mục gốc.
Chạy npx tsc --init để sinh bản đầy đủ kèm chú thích. Phần quan trọng
nhất là compilerOptions:
tsconfig.json (rút gọn)
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"moduleResolution": "nodenext",
"strict": true,
"outDir": "dist"
}
} - ▸tsconfig.json đặt ở gốc dự án; tsc tự đọc nó khi chạy không kèm tên file.
- ▸compilerOptions gom mọi tuỳ chọn quan trọng: strict, target, module, outDir...
- ▸npx tsc --init sinh một bản mẫu đầy đủ chú thích để tham khảo.
strict là tuỳ chọn đáng giá nhất - nó bật cả một nhóm kiểm tra
nghiêm. Từ TypeScript 6, strict bật mặc định, và bạn nên giữ vậy. Hai cái nó
bắt thường xuyên nhất:
noImplicitAny: tham số quên kiểu
function chao(ten) { // ten ngam thanh 'any'
return "Xin chao, " + ten;
} tsc báo
error TS7006: Parameter 'ten' implicitly has an 'any' type. strictNullChecks: quên xử lý null
function dodai(s: string | null): number {
return s.length; // s co the la null!
} tsc báo
error TS18047: 's' is possibly 'null'. Trung thực
Ba tuỳ chọn hay phải đụng khi dựng dự án, và rất dễ lẫn:
- ▸target: tsc sinh JavaScript theo phiên bản nào (vd es2022) - ảnh hưởng cú pháp trong .js.
- ▸module: dùng hệ module nào khi sinh code (ESM, commonjs, nodenext...).
- ▸moduleResolution: tsc TÌM module thế nào (nodenext cho Node hiện đại, bundler cho Vite/webpack).
Mẹo chọn nhanh
"module": "nodenext" + "moduleResolution": "nodenext".
Dự án web qua bundler (Vite, webpack): thường "module": "esnext" + "moduleResolution": "bundler". Khi bí, để tsc --init chọn mặc định hợp lý rồi
chỉnh sau.Không phải thư viện JavaScript nào cũng kèm kiểu. Một tệp .d.ts (declaration) chỉ MÔ TẢ kiểu, không chứa code chạy, để gắn kiểu cho phần JavaScript chưa có:
mylib.d.ts
// Mo ta kieu cho mot module JS chua co kieu
declare module "mylib" {
export function tinhTong(a: number, b: number): number;
} Sau đó import dùng bình thường, TypeScript đã hiểu kiểu. Nhưng trước
khi tự viết, hãy kiểm xem cộng đồng đã làm sẵn chưa - kho DefinitelyTyped cung cấp các gói @types/...:
Cài kiểu cộng đồng
npm install -D @types/node # kieu cho Node
npm install -D @types/lodash # kieu cho lodash - ▸.d.ts chỉ chứa khai báo kiểu (declare), không có code chạy - gắn kiểu cho JS không sửa nguồn.
- ▸@types/... là kiểu do cộng đồng viết ở DefinitelyTyped; cài là dùng được ngay.
- ▸Tự viết .d.ts chỉ khi không có @types sẵn cho thư viện đang dùng.
Một chi tiết nhỏ mà hữu ích: import type chỉ nhập KIỂU, và bị xoá hết
khi biên dịch - đúng tinh thần type erasure ở Bài 1,
nên không sinh ra import JavaScript thừa lúc chạy:
import type
import type { Meo } from "./meo"; // chi lay kieu, bi xoa khi bien dich
import { taoMeo } from "./meo"; // import gia tri thuong (con lai luc chay) Bài tiếp theo: Di chuyển JS sang TS
Câu hỏi thường gặp
Gần như không bao giờ. Từ TypeScript 6, strict bật MẶC ĐỊNH - đó là một quyết định tốt vì strict chính là phần lớn giá trị của TypeScript. Tắt strict (strict: false) làm TS gần như "mù", bỏ qua null và any ngầm. Chỉ tắt tạm khi đang di chuyển dần một dự án JS lớn (Bài sau).
target nói tsc nên SINH ra JavaScript theo phiên bản nào (es2020, es2022...) - ảnh hưởng cú pháp được dùng trong .js. module nói dùng HỆ MODULE nào (ESM, CommonJS, nodenext...) - ảnh hưởng cách import/export được biên dịch. Hai cái độc lập nhau.
Là các gói khai báo kiểu do cộng đồng viết cho những thư viện JavaScript chưa kèm kiểu, lưu ở kho DefinitelyTyped. Vd cài @types/node là có kiểu cho Node. Trước khi tự viết .d.ts, hãy kiểm xem đã có @types/ten-thu-vien chưa.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Từ TypeScript 6, strict mode mặc định thế nào?
- 1
Sinh tsconfig
Chạy npx tsc --init trong một thư mục trống, mở tsconfig.json sinh ra. Tìm dòng strict và target.
✅ Hoàn thành khi: Một tsconfig.json có thật, chỉ ra được dòng strict (bật) và dòng target.
- 2
Bắt no implicit any
Viết một hàm có tham số KHÔNG chú thích kiểu. Biên dịch với strict (mặc định) xem lỗi.
✅ Hoàn thành khi: Ghi lại lỗi TS7006 (implicitly has an any type), và sửa bằng cách thêm kiểu cho tham số.
- 3
Bắt possibly null
Viết một hàm nhận tham số kiểu string | null rồi truy cập .length ngay. Biên dịch xem lỗi, rồi sửa bằng narrowing.
✅ Hoàn thành khi: Ghi lại lỗi TS18047 (possibly null), và bản sửa có kiểm null trước khi dùng.
- 4
Thử tắt strict (rồi bật lại)
Tạm để strict: false trong tsconfig, xem hai lỗi trên biến mất. Rồi bật lại và đọc kỹ chúng quay về.
✅ Hoàn thành khi: Quan sát rõ: tắt strict thì lỗi mất, bật strict thì lỗi quay lại; kèm một câu vì sao nên giữ strict.
- 5
Viết một .d.ts
Giả sử có một module JS tên "mylib" chưa có kiểu. Viết một mylib.d.ts khai báo một hàm của nó, rồi import dùng trong một file .ts.
✅ Hoàn thành khi: File .ts import hàm từ "mylib" và biên dịch sạch nhờ .d.ts; gọi sai kiểu thì tsc báo lỗi.
- 6
import type
Lấy một chỗ đang import một type từ module khác bằng import thường. Đổi sang import type và biên dịch xem .js sinh ra.
✅ Hoàn thành khi: File .js sinh ra KHÔNG còn dòng import cho cái type đó - bằng chứng import type bị xoá.