Dùng module augmentation, một dạng của declaration merging: mở lại module gốc và khai báo thêm thành viên, TypeScript sẽ gộp với khai báo có sẵn.
// types/express.d.ts
import 'express'
declare module 'express-serve-static-core' {
interface Request {
user?: { id: string; role: string }
}
}Bốn điều kiện hay làm hỏng việc này:
1. File phải là module — cần ít nhất một import hoặc export ở top level. Thiếu nó, declare module 'x' bị hiểu là khai báo mới cho một module chưa có type, ghi đè thay vì gộp.
2. Đúng tên module — Express khai báo Request trong express-serve-static-core, không phải express; augment sai tên thì không có tác dụng.
3. File phải nằm trong phạm vi biên dịch — thư mục chứa nó phải khớp include của tsconfig.json (hoặc thêm vào typeRoots/types).
4. Chỉ interface merge được, type alias thì không — đây là lý do các thư viện công khai interface cho phần cho phép mở rộng.
Với global (không thuộc module nào) dùng declare global bên trong một module:
declare global {
interface Window { dataLayer: unknown[] }
}
export {}Cân nhắc: augmentation là hợp đồng ngầm toàn dự án — req.user sẽ hiện ở mọi handler kể cả nơi chưa chạy middleware xác thực.
Khai báo optional (user?) rồi narrow, hoặc dùng kiểu AuthedRequest riêng cho route đã bảo vệ, sẽ an toàn hơn.