A JSDoc in TypeScript's Clothing
Tags: typescript, jsdoc, javascript
Published: 2020-06-30 01:02:25

My recent journey into the Land of the TypeScripts has led me to some odd realizations about what it does - and what it _doesn't_ do.  Specifically, I've become aware of some stunning similarities between the "language" of TypeScript and the _linting tool_ we know as JSDoc.
<br/>

## Ground Rules
Throughout this article I'm going to use a handful of key assumptions.  I freely admit that these assumptions may not always apply to _your_ projects.  And given the way that _your_ team codes, you might feel that there's little in common between TS and JSDoc.  But the following "ground rules" are what lead me to question the utility of one over the other:

1. Given that JSDoc and TS both compile down to plain ol' JavaScript, and given the fact that JS is widely acknowledged as a Functional Programming (FP) language, the "best", "cleanest" code is usually assumed to be that which is broken into its smallest constituent parts.  Specifically, "good" JavaScript code is usually identified as having small, concise functions.  If you've got a bunch of functions that stretch into _hundreds_ of LoC, there's a good chance that other devs will look at them and crinkle their noses.  As the axiom goes: A function does _one thing_, and does it _well_.<br/>

1. If we are keeping our functions concise, the biggest obstacle to writing bug-free code is ensuring clean _inputs_ to our functions.  Similarly, we strive to ensure a consistent _output_ from our functions.  With both TS _and_ JSDoc, it's at least _possible_ to annotate the specific type of _every_ variable. 
 But in my experience, this is rare.  If we have a LoC like this: `const foo = 'bar';` - we rarely bother to specifically annotate that `foo` is of type `string`.  It's obvious to any first-year dev that `foo` is of type `string`.  And there's rarely much utility in codifying this for the compiler.<br/>

1. Because functions (and their associated code files) can often be organized in such a way that they're nowhere near the place where they're being invoked, it can be easy to accidentally pass the "wrong" type of data.  "Bad" data often leads to "bad" results.  So even in TS-heavy (or JSDoc-heavy) codebases, most of the type hinting we're trying to do tends to be focused on function _signatures_.<br/><br/>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/98muqia5m2waleb8o7hc.jpg)
## The Unmasking
I'll be the first to admit that I've never been a huge fan of JSDoc.  Why?  Well, every JSDoc annotation is _a comment_.  And, for some time now, I've generally tried to avoid almost _all_ comments in my code.  I'm a firm believer that, rather than writing comments that _explain_ your code, it's far better to write _self-explanatory_ code.  (That's a subject for a whole other article...)

When I first started doing TS, I had no such reservations.  In fact, I was _excited_ about TS's possibilities.  After all, I could now start writing some _strongly-typed_ JavaScript code.  The possibilities felt immense. But once I started cranking out those _sweet, sweet_ types, some harsh realities began smacking me upside the head:

1. **Still just... JavaScript**<br/>For all the glorious talk about TS's compiler, that compiler is really more of an _interpreter_.  It's just doing a sanity check on your code, and then transpiling it down into plain ol' JavaScript.  JSDoc isn't _exactly_ the same.  It doesn't afford you any extra "compiler" step.  But when you deploy your JSDoc-heavy code, it's still getting run as plain ol' JavaScript.<br/>

1. **Worthless for runtime errors**<br/>Although the path to plain ol' JS isn't entirely identical for TS vs. JSDoc, they both share one critical trait (or, if you will, _fault_): They're both powerless to address _RUNTIME_ errors.  In fact, in some respects, I actually _prefer_ the JSDoc approach because every junior dev understands that comments serve no functional purpose.  And _every_ JSDoc annotation is a comment.  Conversely, it's easy, after writing many hours of TS code, to nearly _forget_ that all that glorious TS magic doesn't even _exist_ at the point that your application is, you know... _running_.<br/>

1. **"Strictly"... malleable**<br/>TS & JSDoc are both as loose - or as strict - as you'd like them to be.  Granted, with TS it's easy to set global configs in such a way that it's more... _conspicuous_ to bypass the compiler.  But at the end of the day, neither one is doing a single thing to change the way that JS operates.  They're only changing the way that you (and the other members of your team) _grok_ the code as you're writing it.<br/>

1. **Verbosity**<br/>One of the things that always turned me off about JSDoc was the gaggle of extra LoC that littered every one of my files.  Sure, those lines of "code" didn't contain any _logic_.  They were all... comments.  But I hated taking a nice, clean, concise function that accepts, say, four inputs and returns one output, and chunking _seven_ extra lines of comments above the function just to _explain_ what those inputs/outputs should be.  Then I started writing TS - and I find that I'm routinely writing many extra LoC, and many extra functions/types/interfaces, and many extra code files, just to achieve what I was previously doing with vanilla JS.  Suddenly, the extra "load" of JSDoc's comments don't seem like such a burden.<br/>

1. **Limited to _JavaScript's_ type model**<br/>It's pretty difficult to construct a "serious" type model when you're confined to the types defined in the underlying language.  With TS _or_ JSDoc, I can annotate that the `firstName` argument is type `string`.  Umm... great?  I mean, sure, it's nice to signify that `firstName` can't be, say, a `Boolean` or an `Array`.  But what if someone passes an _empty_ string for `firstName`?  Is that a "valid" input?  Probably not.  It's still, technically, a `string`.  But neither TS _nor_ JSDoc are adequately equipped to handle these common "gotchas".  To guard against this, we still have to fall back on _runtime_ checks, typically performed at the top of the function.<br/>

1. **Less _coding_ tools than _IDE_ tools**<br/>If you don't believe this, try coding up some tasty TS code... in Notepad++, or Sublime, or any other "basic" text editor.  Then tell me how fun that experience is.  Granted, advanced IDEs are the tools in which nearly _all_ modern code is written.  So I'm not painting this as a "knock" against against either TS or JSDoc.  But most of the "magic" that we get from TS occurs when our IDE puts one of those warning squigglies under our code.  And you can receive the exact same warnings... with JSDoc.<br/>

1. **Conspicuous imperfections**<br/>Whenever you're using _any_ tool designed to better annotate your code, it can be insanely annoying when the IDE/compiler somehow gets it "wrong".  I gave an example of this in my previous article talking about TS object handling.  But the fact is that I've run into the same problem before with JSDoc.  I go to great lengths to fastidiously "define" all of my data types.  And then, at some random place in the function, I get another of those squiggly underlines.  Sometimes this can happen when I _know_ that the code will run perfectly and even after I've gone to great pains to _explain_ to the IDE/compiler how everything should be handled.  But sometimes these tools still don't "get it".  This is a big reason why I rarely use JSDoc unless the project already uses it as a standard.  And it's why I'm already growing somewhat exasperated with TS.<br/><br/>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/t45bdhlbvp1eq7g9nusx.png)
## Trade-Offs
To be clear, I'm not trying to claim that TS _is equivalent to_ JSDoc.  I'm sure that a few TS fanboys have already fired off some defensive comments below - before they even got to this point in the article.

When I started this little TS journey about a month ago, I dove in with the (misguided) belief that TS and JSDoc had _nothing_ in common.  In fact, before I started _writing_ TS, I had never even attempted to compare both of them in the same paradigm.

But the more TS code I write, the more I find myself thinking that TS is "basically" JSDoc, except it's even _more_ verbose, it gets _more_ bogged down in edge-cases (partials, generics, etc), and its "benefits" are even harder to suss out when weighed against the extra overhead of time and cognitive load.

If this sounds like a long rant of "TypeScript bashing", it's _not_.  As far as I can tell (at the time being), the following are the biggest points in TS's favor:

1. It's easier to set global rules in TS that will more easily be enforced across your entire team and throughout your entire codebase.<br/>

1. Assuming that global rules are set, it's easier to spot when any dev is trying to subvert those rules.  An `any` has a tendency to stand out like a sore thumb during a pull request.  Conversely, the way to "subvert" JSDoc rules is to simply... avoid writing the rules altogether.  And it's not nearly such a red flag when some dev has simply _failed to write something_ than it is to catch when he's littered all his code with `any`.<br/>

1. Obviously, there are more "edge cases" that have been accounted for in TS.  Some complex, abstract TS types can be an absolute eyesore to mentally parse.  But at least you _can_ annotate them.  In JSDoc, it can feel borderline impossible to thoroughly annotate those same use cases.<br/>

1. My anecdotal assessment is that TS is a growing, thriving, evolving _community_.  Although I could argue that TS is as much of a "language" as JSDoc, I'll freely admit that JSDoc is fairly... stagnant.  I can't really say that it's "growing" in any meaningful way.  I suppose its skeptics could even claim that it's _dying_ - although it certainly won't be truly going _away_ any time soon.<br/>

1. There are many devs out there who are passionate about working on TS projects.  But even for longtime, hardcore "JS guys", I don't know if there are too many of them getting all giddy just because their next project will be using JSDoc.  This is not an inconsequential observation.  I fully understand that sometimes, if you're building and maintaining a large team of skilled developers, it can be important to utilize the "hot" technologies - even if the "old, stodgy" tech does nearly the same thing and offers nearly the same benefits.<br/><br/>

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0md6pxrt5ukwqppgzhhj.jpg)
## Conclusion
So what say you, TS _fanboys_?  Have I written enough to royally piss you off?  Are you circling your legions of TS acolytes to come burn my house down??

Seriously, though... I don't really _care_ too deeply about TS versus JSDoc.  I'm not trying to trash TS.  I'm not trying to sing JSDoc's praises.  (As I tried to make clear in multiple places above, I actually don't care much for JSDoc _either_.)  This is not some creed imploring everyone to dump their TS codebases and convert them all to JS + JSDoc.

If you already have a huge TS codebase, _of course_ you're gonna stick with TS.  If your team is already littered with hardcore TS fans, _of course_ you're gonna stick with TS.  In fact, even if you're starting from scratch on a "green fields" project, you might look at the strengths/weaknesses of both and decide that TS is the path for you.  _And that's fine._

I just sometimes get a kick out of observing the way that Technology X is held up as "The New Hotness".  And then, when I get in and actually start playing around with that technology, I find myself thinking, "Hmm, this _New Hotness_ feels an awful lot like... the _Old Hotness_."