Bởi vì loại không xác định tại thời gian chạy, tôi đã viết mã như sau để so sánh đối tượng chưa biết, không phải với một loại, nhưng đối với một đối tượng thuộc loại đã biết:
- Tạo một đối tượng mẫu đúng loại
- Chỉ định phần tử nào là tùy chọn
- So sánh sâu đối tượng chưa biết của bạn với đối tượng mẫu này
Đây là mã (giao diện bất khả tri) mà tôi sử dụng để so sánh sâu:
function assertTypeT<T>(loaded: any, wanted: T, optional?: Set<string>): T {
// this is called recursively to compare each element
function assertType(found: any, wanted: any, keyNames?: string): void {
if (typeof wanted !== typeof found) {
throw new Error(`assertType expected ${typeof wanted} but found ${typeof found}`);
}
switch (typeof wanted) {
case "boolean":
case "number":
case "string":
return; // primitive value type -- done checking
case "object":
break; // more to check
case "undefined":
case "symbol":
case "function":
default:
throw new Error(`assertType does not support ${typeof wanted}`);
}
if (Array.isArray(wanted)) {
if (!Array.isArray(found)) {
throw new Error(`assertType expected an array but found ${found}`);
}
if (wanted.length === 1) {
// assume we want a homogenous array with all elements the same type
for (const element of found) {
assertType(element, wanted[0]);
}
} else {
// assume we want a tuple
if (found.length !== wanted.length) {
throw new Error(
`assertType expected tuple length ${wanted.length} found ${found.length}`);
}
for (let i = 0; i < wanted.length; ++i) {
assertType(found[i], wanted[i]);
}
}
return;
}
for (const key in wanted) {
const expectedKey = keyNames ? keyNames + "." + key : key;
if (typeof found[key] === 'undefined') {
if (!optional || !optional.has(expectedKey)) {
throw new Error(`assertType expected key ${expectedKey}`);
}
} else {
assertType(found[key], wanted[key], expectedKey);
}
}
}
assertType(loaded, wanted);
return loaded as T;
}
Dưới đây là một ví dụ về cách tôi sử dụng nó.
Trong ví dụ này, tôi hy vọng JSON chứa một mảng các bộ dữ liệu, trong đó phần tử thứ hai là một thể hiện của một giao diện được gọi là User
(có hai phần tử tùy chọn).
Kiểm tra kiểu của TypeScript sẽ đảm bảo rằng đối tượng mẫu của tôi là chính xác, sau đó hàm assertTypeT kiểm tra xem đối tượng không xác định (được tải từ JSON) khớp với đối tượng mẫu.
export function loadUsers(): Map<number, User> {
const found = require("./users.json");
const sample: [number, User] = [
49942,
{
"name": "ChrisW",
"email": "example@example.com",
"gravatarHash": "75bfdecf63c3495489123fe9c0b833e1",
"profile": {
"location": "Normandy",
"aboutMe": "I wrote this!\n\nFurther details are to be supplied ..."
},
"favourites": []
}
];
const optional: Set<string> = new Set<string>(["profile.aboutMe", "profile.location"]);
const loaded: [number, User][] = assertTypeT(found, [sample], optional);
return new Map<number, User>(loaded);
}
Bạn có thể gọi một kiểm tra như thế này trong việc thực hiện bảo vệ loại do người dùng xác định.