“safe-cast” for TypeScript

Robert Massaioli
4 min readJan 19, 2019

--

Announcing a new package for TypeScript called safe-cast. safe-cast is a TypeScript library for safely casting unknown data to a known type.

You can find it published on NPM.

The safe-cast package on NPM.

What does safe-cast do?

Let’s say that you are writing a web service and you are expecting another service to pass you a blob of JSON that matches this typescript type:

// File: ./InputData.ts
export type InputData = {
id: number;
/**
* @minLength 2
*/
title: string;
lastUpdated: Date;
};

You might be tempted to write the following code in your service:

const rawInputData: any = <data passed from other service>;
const inputData = (rawInputData as InputData);

In this example, we have performed an unsafe cast, we have said “TypeScript — I know that you don’t know what the type of rawInputData is but trust me. I’m pretty confident that it’s an InputData .”

This is not good. What would happen if somebody sent us this data with two mistakes:

const rawInputData = {
id: 1234,
titles: "Hello World, Strange Loop",
updated: new Date()
};

If we then tried to access title or lastUpdated on inputData then TypeScript would not complain but the program would fail at runtime.

What we need is a way to assert, at runtime, that the data we have been given actually matches the type InputData . This is the problem that safe-cast solves.

To use safe-cast to solve this problem, you would write the following code:

import { safeCast, CastError } from 'safe-cast';const rawInputData: any = <data passed from other service>;
const inputData = safeCast<InputData>(
'InputData',
['./InputData.ts'],
rawInputData
);
if (inputData instanceof CastError) {
// Handle the cast failure
} else {
// The cast was successful
}

And there you have it, 100% safe type casting in TypeScript with only one or two extra lines of code than what you would have written anyway. Beautiful!

The general problem

In a nutshell, many programs accept input that:

  • Is JSON (or a subset of JSON)
  • Was created or modified outside of your program's control; by either a human or computer.
  • May not be 100% trustworthy or, at the very least, may simply be accidentally incorrect.

safe-cast validates that the data you accept is in the structure that you expect.

That it what makes it so valuable.

Why did you build safe-cast in the first place?

I wanted the following properties to be true for a type-safe casting library:

  • It should be trivial to add to your existing code.
    safe-cast only requires that you add an import and replace your “trust me Typescript” type casts with a call to the safeCast function. I did not want developers, by default, to have to write their own validation functions for this library to work.
  • It should be performant.
    The first time that you call the safe-cast library and we introspect the types you want to validate performance will take a small 1–2s hit. But for every future call to cast (for most types) will take place in milliseconds.
  • It should cover all use cases.
    There are many complex types that you can write in TypeScript and I wanted this validator to work against everything. To make this possible, safe-cast uses JSON Schema as it’s validation tool. Your types will be converted into JSON Schema using typescript-json-schema and then the incoming data will be validated against that schema using ajv .

These three properties make safe-cast unique.

There must be packages that do this already? Why not use them?

There are plenty of other packages out there that promise runtime validation of your types; but they almost all seem to require that you write your own validation functions instead of just deriving them for free based on your TypeScript types. Packages that fit into this category include:

This is the main problem, they break the principles laid out in the top section, specifically the on that ensures that adding in safe type-casting should be a trivial operation.

Where to next?

The package is very new. I am going to:

  • Try and apply it in real-world situations.
  • Continue to write more comprehensive test cases for the package.
  • Get TypeScript community feedback for the package.
  • As it matures, eventually release a 1.0.0 version of the package.

So, why not give safe-cast a try today and let me know what you think!

--

--