Karena tipe tidak diketahui pada saat run-time, saya menulis kode sebagai berikut untuk membandingkan objek yang tidak dikenal, bukan terhadap tipe, tetapi terhadap objek tipe yang dikenal:
- Buat objek sampel dengan tipe yang tepat
- Tentukan elemen mana yang opsional
- Lakukan perbandingan mendalam dari objek yang tidak dikenal dengan objek sampel ini
Inilah kode (antarmuka-agnostik) yang saya gunakan untuk perbandingan mendalam:
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;
}
Di bawah ini adalah contoh bagaimana saya menggunakannya.
Dalam contoh ini saya berharap JSON berisi array tupel, di mana elemen kedua adalah instance dari antarmuka yang disebut User
(yang memiliki dua elemen opsional).
Pengecekan typeScript akan memastikan bahwa objek sampel saya benar, maka fungsi assertTypeT memeriksa bahwa objek yang tidak diketahui (diambil dari JSON) cocok dengan objek sampel.
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);
}
Anda bisa meminta cek seperti ini dalam implementasi tipe guard yang ditentukan pengguna.