Generics, type transformations, modules và compiler contract
Advanced type tốt bảo tồn quan hệ giữa inputs/outputs; type gymnastics không cải thiện runtime và có thể làm API khó hiểu/chậm compile.
1. Generics và constraints
Type parameter hữu ích khi output giữ quan hệ với input. Constraint giới hạn capability mà implementation dùng; inference thường tốt hơn bắt caller chỉ type argument. Generic không validate runtime và không nên dùng để che schema mismatch.
function first<T>(items: readonly T[]): T | undefined {
return items[0];
}
function sizeOf<T extends {length: number}>(value: T) { return value.length; }
2. Type transformations
keyof/indexed access, mapped/conditional/template-literal types tạo type từ source. Conditional type phân phối trên naked union; infer trích type trong pattern. Utility types thường shallow, không tự deep-copy semantics.
- Giới hạn public type complexity để compile time và error message còn đọc được.
- Kiểm tra distributive behavior bằng type tests, không đoán từ tên utility.
- Runtime object vẫn cần validation khi đến từ network/storage.
3. Type/value namespaces và module resolution
Type-only import/export giúp tránh runtime edge; declaration files mô tả API JS chưa có source types. Runtime module format/resolution phải khớp compiler, bundler và package exports/types conditions. Path alias chỉ là compiler mapping nếu runtime/bundler không rewrite.
| Layer | Question |
|---|---|
| Type checker | Module specifier/type declaration resolve thế nào? |
| Bundler/runtime | Import path, extension, ESM/CJS format có load được không? |
| Package | exports/types/conditions có cùng public surface không? |
4. tsconfig là compiler contract
strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes và useUnknownInCatchVariables biến risk thành feedback. Project references chia graph/build boundary. skipLibCheck giảm time nhưng có thể che declaration conflicts; dùng có lý do và theo dõi.
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"useUnknownInCatchVariables": true
}
}