javascript - Verificați dacă un obiect implementează o interfață în timpul rulării cu TypeScript
Încărc un fișier de configurare JSON la rulare și folosesc o interfață pentru a-i defini structura așteptată:
interface EngineConfig {
pathplanner?: PathPlannerConfig;
debug?: DebugConfig;
...
}
interface PathPlannerConfig {
nbMaxIter?: number;
nbIterPerChunk?: number;
heuristic?: string;
}
interface DebugConfig {
logLevel?: number;
}
...
Acest lucru face convenabil accesul la diversele proprietăți deoarece pot folosi completările automate etc.
Întrebare: există o modalitate de a folosi această declarație pentru a verifica corectitudinea fișierului pe care îl încarc? adică să nu am proprietăți neașteptate?
Răspuns #1
Există o cale, dar trebuie să o implementezi singur. Se numește „User Defined Type Guard” și arată așa:
interface Test {
prop: number;
}
function isTest(arg: any): arg is Test {
return arg && arg.prop && typeof(arg.prop) == 'number';
}
Desigur, implementarea efectivă a funcției isTest depinde complet de tine, dar partea bună este că este o funcție reală, ceea ce înseamnă că poate fi testată.
Acum, în timpul rulării, ai folosi isTest() pentru a valida dacă un obiect respectă o interfață. La compilare, TypeScript recunoaște protecția și tratează utilizarea ulterioară conform așteptărilor, adică:
let a:any = { prop: 5 };
a.x; //ok because here a is of type any
if (isTest(a)) {
a.x; //error because here a is of type Test
}
Explicații mai detaliate aici: https://basarat.gitbook.io/typescript/type-system/typeguard
Răspunsul #2
Iată o altă alternativă, special pentru asta:
ts-interface-builder este un instrument pe care îl rulezi la timpul de construire pe fișierul tău TypeScript (de exemplu foo.ts) pentru a construi descrieri la runtime (de exemplu foo-ti.ts).
ts-interface-checker folosește acestea pentru a valida obiectele în timpul rulării. De exemplu.
import {createCheckers} from 'ts-interface-checker';
import fooDesc from 'foo-ti.ts';
const checkers = createCheckers(fooDesc);
checkers.EngineConfig.check(someObject); // Succeeds or throws an informative error
checkers.PathPlannerConfig.check(someObject);
Puteți folosi metoda strictCheck() pentru a vă asigura că nu există proprietăți necunoscute.
Răspunsul #3
Nu.
În prezent, tipurile sunt folosite doar în timpul dezvoltării și al compilării. Informațiile despre tipuri nu sunt traduse în niciun fel în codul JavaScript compilat.
De pe https://stackoverflow.com/a/16016688/318557, așa cum a subliniat @JasonEvans
Există o problemă deschisă din iunie 2015 despre aceasta în repo-ul TypeScript: https://github.com/microsoft/TypeScript/issues/3628
Răspunsul #4
Iată o modalitate bună. Poți converti o interfață TypeScript într-un schema JSON folosind typescript-json-schema, de exemplu.
typescript-json-schema --required --noExtraProps \
-o YOUR_SCHEMA.json YOUR_CODE.ts YOUR_INTERFACE_NAME
Apoi validează datele la rulare folosind un validator de schemă JSON, cum ar fi ajv, de exemplu.
const fs = require('fs');
const Ajv = require('ajv');
// Load schema
const schema = JSON.parse(fs.readFileSync('YOUR_SCHEMA.json', {encoding:"utf8"}));
const ajv = new Ajv();
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
var validator = ajv.compile(schema);
if (!validator({"hello": "world"})) {
console.log(validator.errors);
}
