Khi khai báo kiểu tương tự lặp trong TypeScript, ta tìm cách tính kiểu kết quả từ kiểu đầu vào. Điều quan trọng hơn số ký tự ngắn là quan hệ giữa kiểu có rõ cho người đọc không. Bài này dùng dịch vụ thông báo giao hàng giả định để xem kiểu điều kiện, infer, rồi tách với kiểm dữ liệu ngoài thực đúng không.
1. Kiểu điều kiện là nhánh nhận kiểu làm đầu vào
Tài liệu kiểu điều kiện chính thức giải thích cú pháp chọn kiểu kết quả theo extends. Ví dụ dưới tạo kiểu literal boolean tùy có phải kiểu chuỗi. Đây không phải hàm kiểm chuỗi khi chạy.
type IsText<T> = T extends string ? true : false;
type NameIsText = IsText<'parcel'>; // true
type CountIsText = IsText<3>; // false
Giả sử hàm thông báo nhận định danh chuỗi, hàm xử lý trong nhận định danh số. Trước dùng kiểu điều kiện phải giải thích vì sao tách hai định danh. Khác nghĩa thật thì tên riêng giúp ích; chỉ khác ký hiệu thì thống nhất đầu vào có thể dễ đọc hơn. Không dùng kỹ thuật kiểu che mơ hồ thiết kế dữ liệu.
Khi xem kiểu, ghi cặp đầu vào, kết quả mong đợi. Tách chuỗi, số, union, đầu vào bất ngờ thành ví dụ nhỏ giảm gánh đọc khai báo phức tạp. Kiểm kết quả trong chú thích có khớp kiểu editor suy ra. Tên kiểu tự nhiên vẫn có thể tính kết quả khác.
2. Phân phối union đổi nghĩa mảng
Tham số kiểu nằm trực tiếp bên trái điều kiện sẽ phân phối điều kiện lên từng thành viên union. Muốn ngăn, xử lý cả union như một thì so dạng bọc ngoặc vuông.
type SeparateLists<T> = T extends unknown ? T[] : never;
type Together<T> = [T] extends [unknown] ? T[] : never;
type A = SeparateLists<string | number>; // string[] | number[]
type B = Together<string | number>; // (string | number)[]
const a: A = ['a', 'b'];
const b: B = ['a', 1];
Đầu là mảng chỉ chuỗi hoặc chỉ số. Sau cho chuỗi, số cùng một mảng. Kết quả hợp tùy cả danh sách giao chỉ một loại mã hay mỗi mục cho loại khác. Cùng thấy ngoặc vuông nhưng hợp đồng hai mảng khác.
Khi có vấn đề thực, hãy đưa từng thành viên đầu vào thay vì đọc cả utility phức tạp một lượt. So kết quả chuỗi, số, union cả hai. Rõ có định phân phối không sẽ giải thích được vì sao thêm ngoặc. Hồ sơ kiểm kiểu nên có ví dụ giá trị cho phép, không chỉ kết quả cuối.
3. infer đặt tên, lấy kiểu trong cấu trúc
infer dùng đặt tên một phần cấu trúc khớp trong kiểu điều kiện. Ví dụ sau là kiểu nhỏ bỏ một lớp Promise.
type OneResult<T> = T extends Promise<infer Value> ? Value : T;
type Parcel = OneResult<Promise<{ tracking: string }>>;
type ParcelList = OneResult<Promise<string[]>>;
Mã không chạy hay đợi tác vụ bất đồng bộ, chỉ diễn dạng kết quả ở lúc biên dịch. Tên hàm như Resolved có thể gây ấn tượng giá trị đã tới, nên xem ngữ cảnh dùng kiểu. Chờ lúc chạy vẫn cần xử lý bằng mã bất đồng bộ.
Cần kiểu kết quả đợi đệ quy thì xem utility chuẩn Awaited trước mở mã một lớp tự làm mãi. Kiểu giảng dạy đơn giản khác yêu cầu công cụ dùng chung. Nhóm đưa utility mới nên ghi đầu vào khác kết quả chuẩn và vì sao cần khác.
4. Nối tên sự kiện bằng template literal
Kiểu template literal diễn tổ hợp literal chuỗi bằng kiểu. Với dịch vụ giao hàng, có thể lấy tên sự kiện kết hợp vùng, hành động.
type Scope = 'parcel' | 'address';
type Action = 'created' | 'updated';
type EventName = `${Scope}:${Action}`;
const event: EventName = 'parcel:created';
Tên sai chính tả phát hiện khi biên dịch nhưng mọi tổ hợp có hợp lệ dịch vụ thật không là chuyện khác. Ví dụ chỉ hỗ trợ sự kiện xóa địa chỉ thì tích đơn giản vùng-hành động có thể không diễn đúng quy tắc. Lúc đó xét trước thiết kế ánh xạ rõ sự kiện cho phép và payload.
Sự kiện nhiều thì người đọc dễ tìm tên thật cũng quan trọng. Hơn nối nhiều cấp luật tự ghép, có thể để tên gửi hệ ngoài thấy ở một file. So người mới phát hiện sự kiện sai trước, sau trừu tượng hóa. Độ tinh của kiểu và dễ dùng cần đánh giá cùng.
5. JSON ngoài phải kiểm lúc chạy
Gắn kiểu User hoặc Parcel vào phản hồi API không bảo đảm phản hồi thực có cấu trúc đó. Xem cách nhỏ nhận giá trị ngoài là unknown rồi kiểm trường cần.
function hasTracking(value: unknown): value is { tracking: string } {
return typeof value === 'object' && value !== null
&& 'tracking' in value && typeof value.tracking === 'string';
}
const incoming: unknown = { tracking: 'DEMO-001' };
if (hasTracking(incoming)) console.log(incoming.tracking);
Kiểm này chỉ xác nhận tracking là chuỗi, không kiểm mã vận đơn tồn tại hay người có quyền xem chuyến. Tách thu hẹp kiểu, quy tắc nghiệp vụ, kiểm quyền thành trách nhiệm riêng. Tài liệu Narrowing chính thức giải thích thu hẹp thông tin kiểu qua điều kiện.
6. Thứ tự nhỏ để chọn công cụ kiểu
Trước ghi hai giá trị thật cho và hai từ chối. Tiếp diễn nghĩa bằng union thường, khai báo đối tượng rõ. Còn quan hệ lặp thì dùng kiểu điều kiện, infer sẽ có lý do rõ. Nếu đọc khai báo lâu hơn nhiều, có thể chỉ trích phần chung, để phần khác kiểu thường.
Cuối chạy kiểm kiểu và kiểm lúc chạy riêng. Xác nhận compiler từ chối tên sự kiện sai, và chương trình giải thích lỗi khi máy chủ thiếu trường là bổ trợ nhau. Kiểm ví dụ nhỏ xong nối tới ranh giới đầu vào thật mới giúp chuyển kiểu phục vụ thiết kế ứng dụng an toàn.