A story of why you should use strong types in Javascript team projects

tq-bit - Jan 15 '22 - - Dev Community

TL: DR - Because a breaking change in an NPM module - mistakenly introduced by a team member - is WAY easier to spot if your code is typed. There probably is a lot of other good reasons, too.

1. If you don't want to use Typescript, use JSDoc typing. In VSCode, activate it under Preferences > Settings by adding

"javascript.implicitProjectConfig.checkJs": true
Enter fullscreen mode Exit fullscreen mode

2. Instead of

function prepareStoredProcedurePayload(file) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

write:

/* 
 * @param {formidable.File} file
 */
function prepareStoredProcedurePayload(file) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Or with Typescript:

function prepareStoredProcedurePayload(file: formidable.File):  {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

When I was confronted with typing, it seemed like a redundancy. What would I need all the overhead for? I enjoy dynamic typing. And sometimes even the slight confusion when looking at legacy code. So this is the story of how one debugging session and an NPM module convinced me that it really isn't redundant. Especially not when working on bigger projects.

This article will be divided into two parts:

  1. The first one will tell a little story of how I screwed up with Javascript.
  2. The second will include my first migration attempt and a checklist.

If you'd like to skip the story, click here to move directly to the migration checklist.

A story of 'Why Typescript?'

Earlier this year, I was confronted with typing for the first time. Since Javascript was my first language, doing it seemed awkward.  Yes, I know that variable is a string. I've just done the assignation. Why is this relevant?

A naive thing to say. Perhaps a bit arrogant.

Because Typescript shines when working on bigger team projects.

In this case, my fellow team member would be my future me and a colleague. I came back to the project with a change request. Extend a single functionality for a file upload service. Written in Javascript. Actually, the same one from my earlier article. No biggie. Right?

So I went to work. And like a good little coder, I did some chores on the way. Implement the feature, leave the place cleaner than you found it. So all changes were done and tested - time for the code review. And, fortunately, at this stage, the whole thing went bonkers (it crashed).

Jeez, I thought. This service again. What happened?

I followed the same Git-driven workflow as always. But this time, something was different. A colleague of mine had updated the formidable library from v1 to v2.

This introduced a change in the - you might have guessed - File - type. Suddenly the property that was previously called file.name changed to file.originalFilename. And some other props changed, too. This would cause a problem with the stored procedure. It requires a filename, a mime-type, size, and so forth to function.

On top of this, there was no error checking for these props. So there was no obvious stack trace to identify what was going on.

So one debugging session later, I had it figured. And I was upset. This issue could've been prevented so easily. Not even with the Typescript overhead, but by using JSDoc typing

Instead of:

function prepareStoredProcedurePayload(file) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

I should have written:

/* 
 * @param {formidable.File} file
 */
function prepareStoredProcedurePayload(file) {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

And activate TS checking with this line under Preferences > Settings (VSCode):

"javascript.implicitProjectConfig.checkJs": true
Enter fullscreen mode Exit fullscreen mode

It would then have informed me that type File does not have property 'name'. These three lines would have saved me a good two hours of debugging work.

Lesson learned: Types are useful. Especially in distributed apps with external libraries. They do create an overhead. But in dev teams, the value of code trust quickly outweights the cost of it. Even if you want to keep your JS codebase, you can (and should) still extend your projects with JSDoc types.

As you can imagine, after I discovered JSDoc typing, the next logical step will be proper typing with Typescript. If not for this project, then for the next one.

To prepare for the inevitable, I developed and migrated a Node.js application. And I've created a checklist on the way. If you recently found yourself in a similar situation as I did, you're invited to read on and discover the joy of using types.

At the moment this article is released, I am not (yet) finished writing the whole followup. Till it's ready, you can already take a look into the WIP repository.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .