3 TypeScript-ish Solutions For Your Type Checking Needs in JavaScript

For those times you need to type-check but you just refuse to use TypeScript

Fernando Doglio
Bits and Pieces
Published in
7 min readOct 26, 2020

--

Type checking has proven to be a very valued feature for many JavaScript developers, to the point where they’ve made the switch entirely from JS to TypeScript.

And thanks to Deno now, we don’t even need to worry about transpiling our code, it really feels like a fully fledged language. However, while the jump is very doable for some, it’s actually massive for others who consider it not worth it (i.e the benefits they would get out of it are not that many).

However, we can probably all agree that there are certain benefits to having, at least, type checks on our code. There are some errors we would be able to avoid by making sure we’re dealing with the correct data types, especially for function / method calls.

So, in this article, I’m going to cover 3 libraries that provide that type of functionality to your JavaScript code, without you having to make the switch to a completely new language. Why 3 you ask? Because they all act on different levels as you’re about to learn, this will give you the freedom to pick the one you need based on the level of commitment you have to this feature.

TypeCheck

Let’s start with the most basic library we’ll cover today. Mind you, by basic I mean through our POV, I’m sure internally it’s quite complex, however, thanks to TypeCheck, we’ll be able to directly validate the type of single variables from our code.

First things first, this library is available through NPM if you want to test it, so you can install it simply by writing:

npm install type-check

Once installed, you can start using it directly in your code. There is really one method you want to work with: typeCheck (unsurprisingly enough).

This method will receive two parameters, the type definition and the actual variable you’re trying to check during runtime.

You can see a very basic example there, taken from their own documentation. This is how Type Check works, you can, of course, have your type definitions somewhere else, and reference them when you call the method. The key takeaway here is that you need to manually write the type-checking logic into your code, this will not happen automatically, but that also gives you direct control over where you use it and what you do with it.

You can even push it further and create a form of function factory that contains intrinsic type checking on its parameters and return type, such as this:

I’m sure you can come up with a better solution, but consider the implications: we just used TypeCheck to create a functions factory that will make sure it’ll throw an exception when we pass it the wrong parameter types during execution. Granted, a code like this would fail directly during compilation for TypeScript, but at least now you’ve gained some of that power back, without having to use a completely new language.

Types definitions are very intuitive, for instance, we can take the above function, and use it to deal with arrays like this:

The typeCheck method we’ve been using actually accepts an optional third parameter that allow us to create custom types, such as the one seen below:

This is the equivalent of defining your own types in TypeScript, allowing you to create some very interesting logic into your type-checking functions.

Now, this is all nice and interesting, but it also requires quite a lot of work from our part. Let’s take a look at other options.

Typify

If you’re looking to create custom functions that benefits from type-checking capabilities, the above solution might be too cumbersome. Instead, you can rely on Typify, a library designed specifically for that.

You can install it from NPM like with others:

npm install typify

And once that is done, we can just require it and directly use it like this>

This function is the equivalent of the one we defined before, you can see that the first argument passed to typify is a somewhat elaborated formal definition of the function’s signature. With that, the module is capable of verifying both, the received parameters and the returned value. If there is a problem with any of them (like with the last line), an exception will be thrown.

Essentially the behavior is the same as the one we manually wrote with the previous module, but now instead, you’re getting it out of the box. For more complex or elaborate definitions, please review their entire documentation, because they do provide support for some interesting combinations.

You can also use the check method to perform individual variable checks, like with the previous solution. You can specify the type and then the actual variable being checked.

This combination gives you both, control over the small sections of your code that only require variable-level checks and over complete functions being defined as well. So if you think about it, it is definitely a step up from the previous module. However, we’re still having to manually write all that into our logic.

There is one more option, which brings us very close a TypeScript-like solution, without having to change our code completely.

TypeOnly

This module attempts to be the pure typing section of TypeScript, meaning you can create completely compatible type definitions and parse them with this module. In fact, you can extract definition files (i.e .d.ts files) directly from TypeScript-based projects, and use them on your own.

You can install it, as we’ve seen before, through NPM:

npm install typeonly

You can now also create a types folder inside your project and add the following script to package.json :

"scripts": {
"typeonly": "typeonly --bundle dist/types.to.json --source-dir types"
},

So now, you can add your .d.ts files inside the types folder and run the following command:

npm run typeonly

With that, you can now find inside the dist folder, a types.to.json file containing the type definition you’ll be using from within your code.

Now in order to use these type definitions in your code, you’ll have to install another project from the same team: the validator.

Using the types JSON

Install the module using NPM like before:

npm install @typeonly/validator

And now, just use that validator module to create a new validator based on the JSON you just created in the previous step. Then it is just a matter of validating your data against that definition.

Sample code taken from TypeOnly documentation

This is of course, with a type definition as follows:

Sample type taken from TypeOnly documentation

The code really explains itself, except for a very minuscule detail: notice the type definition file’s name: drawing.d.ts

When you parse and translate that file into the final JSON, the name of it is kept, which is why on line 16 of the JavaScript code, you’ll see how that name is being referenced as the first parameter of the method validate .

This is definitely awkward design, because you have to start worrying about where did the types come from in order to use them in your validation process.

Now, this is definitely not a very transparent process, considering how you still need to manually specify where to implement the type checking. But then again, you’re still working in JavaScript (in other words,you’re not having to transpile your code from something else) and you gain full control over how and where that validation takes place.

The only big limitation TypeOnly current has, is Generics. TypeScript has been giving Generics a lot of power lately, and if you’re looking to take advantage of that, TypeOnly will not give you that option yet.

Closing words

Static type check in JavaScript is not possible without transpiling your code from other syntax, such as TypeScript, or Flow, or others, but dynamic type checking is definitely possible and although it can’t happen transparently as we would like (given it’s not a native feature of the language), it can be customized to happen exactly where and how you want it:

  • If you only want to check single variables here and there, you can take advantage of TypeCheck.
  • If you’re looking to extend that into function definition, then maybe moving on to Typify could work wonders.
  • Finally, if on the other hand, you’re looking to re-use TypeScript type definition files, then you’ll want to go with TypeOnly.

What are your thoughts on dynamic type checks in JavaScript? Do you think the extra work required is worth it? Leave a comment down below and share your thoughts!

--

--

I write about technology, freelancing and more. Check out my FREE newsletter if you’re into Software Development: https://fernandodoglio.substack.com/