Nếu bạn muốn JSON của mình có kiểu Typecript đã được xác thực, bạn sẽ cần phải tự mình thực hiện công việc xác nhận đó. Điều này không có gì mới. Trong Javascript đơn giản, bạn sẽ cần phải làm như vậy.
Thẩm định
Tôi thích thể hiện logic xác thực của mình như một tập hợp các "phép biến đổi". Tôi định nghĩa a Descriptor
là một bản đồ của các phép biến đổi:
type Descriptor<T> = {
[P in keyof T]: (v: any) => T[P];
};
Sau đó, tôi có thể tạo một hàm sẽ áp dụng các biến đổi này cho đầu vào tùy ý:
function pick<T>(v: any, d: Descriptor<T>): T {
const ret: any = {};
for (let key in d) {
try {
const val = d[key](v[key]);
if (typeof val !== "undefined") {
ret[key] = val;
}
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
throw new Error(`could not pick ${key}: ${msg}`);
}
}
return ret;
}
Bây giờ, tôi không chỉ xác thực đầu vào JSON của mình mà còn đang xây dựng kiểu Typecript khi tôi tiếp tục. Các kiểu chung chung ở trên đảm bảo rằng kết quả suy ra các kiểu từ "các phép biến đổi" của bạn.
Trong trường hợp biến đổi gây ra lỗi (đó là cách bạn sẽ triển khai xác thực), tôi muốn kết hợp nó với một lỗi khác hiển thị khóa nào đã gây ra lỗi.
Sử dụng
Trong ví dụ của bạn, tôi sẽ sử dụng điều này như sau:
const value = pick(JSON.parse('{"name": "Bob", "error": false}'), {
name: String,
error: Boolean,
});
Bây giờ value
sẽ được nhập, vì String
và Boolean
cả hai đều là "máy biến áp" theo nghĩa chúng nhận đầu vào và trả về đầu ra đã nhập.
Hơn nữa, ý value
muốn thực sự là loại đó. Nói cách khác, nếu name
thực sự là 123
, nó sẽ được chuyển đổi để "123"
bạn có một chuỗi hợp lệ. Điều này là do chúng tôi đã sử dụng String
trong thời gian chạy, một hàm tích hợp sẵn chấp nhận đầu vào tùy ý và trả về a string
.
Bạn có thể thấy điều này hoạt động ở đây . Hãy thử những điều sau để thuyết phục bản thân:
- Di chuột qua
const value
định nghĩa để xem cửa sổ bật lên hiển thị đúng loại.
- Hãy thử thay đổi
"Bob"
để 123
và chạy lại mẫu. Trong bảng điều khiển của bạn, bạn sẽ thấy rằng tên đã được chuyển đổi đúng thành chuỗi "123"
.