I am working on the UI of an app using typescript. At the same time others work on providing me data. We agreed on the data contract however the process is error prone and I keep getting invalid data objects from the server. So my question is can I somehow validate dynamic objects (at run time) using some of my interfaces defined in typescript?
As it stands, TypeScript interfaces are purely compile time entities so there is no way to do any sort of runtime validation let alone even knowing what interfaces existed at compile time. Thus, the answer would seem to be one of:
- Write some tool to convert TypeScript interfaces to some runtime object representation that you can use to validate your objects, or:
- Duplicate your TypeScript interfaces as some runtime object representation
You could use JSON-schema as your runtime representation, as many validators exist on Github. A TypeScript interface --> JSON Schema converter is something I hope someone makes at some point, but as far as I'm aware doesn't exist as yet.
As Brian points out, interfaces manifest themselves only at compile time and are used as so-called named-types by the compiler. Section 7 of the language specification describes this as follows:
Interfaces have no run-time representation—they are purely a compile-time construct. Interfaces are particularly useful for documenting and validating the required shape of properties, objects passed as parameters, and objects returned from functions.
Further down in section 7.4 of the spec there is a nice description of dynamic type checks in Typescript:
TypeScript does not provide a direct mechanism for dynamically testing whether an object implements a particular interface. Instead, TypeScript code can use the JavaScript technique of checking whether an appropriate set of members are present on the object...
The example in the specification defines three interfaces:
interface Mover {
move(): void;
getStatus(): {speed: number;};
}
interface Shaker {
shake(): void;
getStatus(): {frequency: number;};
}
interface MoverShaker extends Mover, Shaker {
getStatus(): { speed: number; frequency: number; };
}
MoverShaker
combines Mover
and Shaker
into a new compound interface. To validate at runtime that a given type fulfills interface MoverShaker
, you can use Javascript code as follows:
var obj: any = getSomeObject();
if (obj && obj.move && obj.shake && obj.getStatus) {
var moverShaker = <MoverShaker> obj;
...
}
In order to have compile-time checking in Typescript, you need to define interfaces for the types that are exchanged between the two parts of your application. Currently, you have to write dynamic checking code (as above) manually. Hence, static type and dynamic checking code may at some point deviate if you forget to update them in sync. As Brian points out, it would be nice to have a tool that generates the code automatically.
Try my dynamic interface checker if you like, here's an example (full example):
interface PhysicalObject { color : Color; intact : bool; weight : number; }
class Car implements PhysicalObject {
public intact = true;
constructor(public color : Color, public weight : number) {};
}
function scratch(aCar : Car) {
typeCheck(JSVenv, arguments, schemas, ["PhysicalObject"]);
console.log("Scratching the car!");
aCar.intact = false;
}
When code equivalent to scratch({ intact: 42, color: Color.RED })
is called, an error like this is thrown:
AssertionError: Runtime typecheck failed on argument number 1:
Value: { color: 0, weight: 'four', intact: true },
Schema: ...,
Error reports (length 1):
[
{
uri: 'urn:uuid:b9b8e6fd-b14b-490d-9372-d2bd22e8a246#/weight',
schemaUri: 'urn:uuid:c76ddd92-15da-43a6-831e-6717f253efe5#/properties/weight',
attribute: 'type',
message: 'Instance is not a required type',
details: [ 'number' ]
}
]
See the main page for instructions: https://github.com/ysangkok/typescript-interface-to-jsonschema
I'd add automatic typechecking, but I'd need something like node-falafel for TypeScript.
© 2022 - 2024 — McMap. All rights reserved.