เนื่องจากไม่ทราบชนิดของรันไทม์ฉันจึงเขียนโค้ดดังนี้เพื่อเปรียบเทียบออบเจ็กต์ที่ไม่รู้จักไม่ใช่กับประเภท แต่เปรียบเทียบกับออบเจ็กต์ประเภทที่ทราบ:
- สร้างวัตถุตัวอย่างของประเภทที่เหมาะสม
- ระบุองค์ประกอบที่เป็นตัวเลือก
- ทำการเปรียบเทียบวัตถุที่ไม่รู้จักของคุณกับวัตถุตัวอย่างนี้อย่างละเอียด
นี่คือโค้ด (อินเตอร์เฟสที่ไม่เชื่อเรื่องพระเจ้า) ที่ฉันใช้สำหรับการเปรียบเทียบแบบลึก:
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;
}
ด้านล่างเป็นตัวอย่างของวิธีการใช้งาน
ในตัวอย่างนี้ฉันคาดว่า JSON จะมีอาร์เรย์ของ tuples ซึ่งองค์ประกอบที่สองเป็นตัวอย่างของอินเทอร์เฟซที่เรียกว่าUser
(ซึ่งมีองค์ประกอบที่เป็นตัวเลือกสองรายการ)
การตรวจสอบชนิดของ TypeScript จะทำให้แน่ใจว่าวัตถุตัวอย่างของฉันถูกต้องจากนั้นฟังก์ชัน assertTypeT จะตรวจสอบว่าวัตถุที่ไม่รู้จัก (โหลดจาก JSON) ตรงกับวัตถุตัวอย่าง
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);
}
คุณสามารถเรียกใช้เช็คเช่นนี้ในการใช้งานของยามชนิดที่ผู้ใช้กำหนด