Thankfully, now there are many solutions out there to validate type at runtime. Almost too many. But these validators are optional, so the problem remains for those who don't use them.
TypeScript code, when compiled with a pure TypeScript compiler, has all the type
definitions stripped. Code that assumes unknown
or any
with as
may fail.
type Circle = { diameter: number };
const circle = (await receiveCircle()) as Circle; // `unknown` asserted as 'Circle'
const diameter = Math.PI * circle.diameter; // possibly NaN
This problem often arises on the JavaScript runtime's system's boundary e.g. network call, file access, inter-process communication.
Anyway, when people start to realize, it is duct-taped with manual runtime type checking
if ("diameter" in circle && typeof circle.diameter === "number") {
// valid
} else {
// invalid
}
Soon after, genius folks created validators like
zod
and
io-ts
. With that, defining the type and
validator becomes a one-step process.
const Circle = t.type({
diameter: t.number,
});
const maybeCircle = await receiveCircle();
if (!Circle.is(maybeCircle)) {
throw new Error("not circle");
}
const circle = maybeCircle;
The lack of a native validator isn't as depressing as other sources of complications. But the fact that TypeScript is in a way weak-typed forces us to treat these third-party validators as essentials.