TypeGuardian

Explanation

Defining all your types and interfaces using TypeScript provides a degree of type safety when using JavaScript, as it's possible to catch potential errors while writing code, instead of having to see them in execution. However, this is a challenge when it comes to communicating with external systems, where we cannot guarantee that the data they send us will align with the definitions we have written.

The solution to this is to write a typeguard function, which checks that an object meets all of our expectations when we expect it to be of a particular type.

However, the task of writing a typeguard is quite tedious. Luckily, it's also quite formulaic, which means it's often possible to generate a typeguard function based off a type definition. That's what this tool, TypeGuardian, is for.

Options

TypeGuardian will remember your preferred options. Here is how they work:

Allow enhanced debugging

When this option is enabled, TypeGuardian will generate a function that uses TypeScript's asserts keyword, which will throw an error if a tested value doesn't meet your type requirements. This function is then called within your type's generated typeguard function, which returns a boolean value as normal.

By throwing an error, instead of just returning a boolean, it's possible to provide information as to how the typeguard fails.

In order to expose this information, typeguard functions generated with this option enabled will have an optional errorLogger argument, which will allow you to log the failure message to somewhere like the console. For example, you might call isMyCustomType(value, console.error) to log a failure message to the console as an error.

Any nested typeguards, for more complex types, will also be passed this errorLogger function. So it's expected that they will all have been generated with this option enabled.

Indentation

This option allows you to select your preferred type of indentation.

Strategy

The typeguard functions generated here follow a certain format:

1. Type assertion

TypeGuardian starts by asserting that the value being tested is of the correct type, which will allow us to access the properties that we want to check for.

Usually, type assertions in TypeScript can be unsafe and should be avoided where possible. In this case, because we're checking it piece by piece rather than actually trying to use any of it, we shouldn't run into trouble.

2. Object check

Before checking any properties, we check that the value is an object. Because checking typeof null also results in 'object', we also need to check that the value is not null.

3. Check each property

This is the main part of the typeguard function. Property by property, we check that each one has the correct type.

As soon as we find any property that doesn't meet our expectations, we return false because the value has failed our type check.

These conditions are each written in an "unless" form, where the innermost part of the condition is a positive assertion (e.g. if a property should be a string, it checks that it is a string), but then that positive part is inverted. So it can be read as "unless this property meets our expectations… return false".

There are several types of check that can be done here. The most basic is checking the result of using the typeof operator, when checking for primitive types like string. TypeGuardian can also handle union types and array types.

4. Return true

If the typeguard function passes through all our checks without a single failure, then we can say that the value meets our expectations, and return true.

Shortcomings

TypeGuardian is a fairly simple and rigid tool, and it relies on type definitions fed into it meeting certain criteria: