A while ago, I tweeted about the reason why I don’t use TypeScript in more of my personal projects.
It’s not that I dislike TypeScript and that I don’t use it at all. I actually enjoy using it in my Angular 2 projects. The reason I don’t use it more often however, is because because I’m being forced to use type definitions when I want to use 3rd party modules. When it comes to these 3rd party modules, it feels like TypeScript is more all in or nothing in comparison to it’s direct competitor, Flow.
First of all, let me explain what type definitions are. Type definitions or type declarations describe the shape of an external module. It describes the available methods of the module, the return type, the parameters and so on.
To give you an example, let’s assume we use a concat module that concatenates two strings a and b. The definition file would look like this.
After installing the module, together with the type definitions, we can start using it.
That example works perfectly. Both arguments provided, foo and bar, are from the type string and thus match the definition file. So what if we change one of the arguments to be a number instead?
This will result in the following error when transpiling.
index.ts(3,13): error TS2349: Cannot invoke an expression whose type lacks a call signature.
The major benefit of these type definitions is to catch errors early on in the development process, at build time instead of at runtime.
A lot of work has been done by the OpenSource community to create type definitions for numerous projects. The DefinitelyTyped project hosts type definitions for more then 2000 package and recently typings started adding these type definitions to npm inside the @types namespace. With the typings cli tool, you can easily search and install the definition files from both npm and DefinitelyTyped.
But as you will notice, not all the modules you want to use in your project actually have these type definitions. So let’s go back to our previous example.
What would happen if we didn’t had these type definitions for our concat module?
index.ts(1,25): error TS2307: Cannot find module 'concat'.
Exactly, the transpiler will fail because it does not recognize the concat module.
From this point on, you have two options. The first option would be to create the entire definition file yourself and publish it to npm or DefinitelyTyped. While this could take some time, it could be beneficial in the long run, especially when you use that module a lot. This approach is perfectly feasible for small one-line modules, but not so much for very large modules like for example axios. In that case, you would probably go for option number two, the easy way. You can always define a module as type any. In TypeScript 2.0, the syntax is even made a little bit easier and looks like this.
Because it is the fastest and easiest way of solving this, the any-type approach is likely the one being used the most.
A great benefit when installing type definitions with typings is that it will create a typings.json file for you. This file keeps track of what type definitions are installed in your project. This way, you don’t have to commit all the type definitions to git. Except for the ones you created manually of course.
So TypeScript team, That’s why I have a suggestion for you. You can already turn off the noImplicitAny flag which basically assumes that all the variables without explicitly declared type are of type any. Why couldn’t we add an extra flag, a noImplicitAnyModule flag? When you turn off this flag, it will assume that every module without type definition is of type any. And just add a warning to the console while transpiling that this flag is being turned off and should be used with care. Just to make sure that developers know what they are doing.