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

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.
This is of course, with a type definition as follows:
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!
Share your reusable components between projects using Bit
Bit (GitHub) makes it simple to share, document, and organize independent components from any project.
Use it to maximize code reuse, collaborate on independent components, and build apps that scale.
Bit supports Node, TypeScript, React, Vue, Angular, and more.
