Article summary
My default when starting a new project is TypeScript. It could be the smallest deliverable ever—like a single marketing webpage—and I’ll still whip out that TypeScript compiler in a flash. But what about when TypeScript isn’t an option? Maybe a build step isn’t feasible. Or it’s just a really short script and TS feels like overkill. Or maybe you’re handing off the code to someone who wants to make changes on the fly without worrying about compilation.
Okay, that last one is oddly specific… because it happened to me. I was writing a piece of code that wasn’t at its final destination and was likely going to be edited. I couldn’t guarantee the updated code would be run through tsc
again, so I needed to ensure it remained readable and safe to modify. I won’t get into the details, but it’s safe to say TypeScript just wasn’t an option. 🙂↔️
This presented a big problem: I lost my red squigglies! I couldn’t hover over functions to see their signatures. And maybe worst of all—I lost my dev workflow of defining a function’s inputs and outputs before writing its implementation.
Enter JSDoc
How could I get back all that goodness without a build step? Well, you read the title: enter JSDoc, baby.
If you’re unfamiliar, JSDoc is an API documentation generator for JavaScript. It looks like this:
/**
* Represents a book.
* @constructor
* @param {string} title - The title of the book.
* @param {string} author - The author of the book.
*/
function Book(title, author) {
//... code here
}
There can be more or less to it—think return types or just descriptions—but you get the idea. The best part? It’s just comments. No build step. No transpilation. Just good old inline documentation that powers your editor.
I first heard about JSDoc on an episode of JS Party 🪦 (RIP to my favorite podcast) when they discussed the TC39 Type Annotations proposal. JSDoc made headlines again when DHH ditched TypeScript in favor of JSDoc for Turbo 8.
Back to my problem: I remembered JSDoc existed and figured I’d give it a shot. Worst case? It would at least document my code better and help me return to my workflow of defining function I/O. But it actually took me way farther than I expected.
Turns out, the TypeScript compiler supports JSDoc! Even better? You know what popular IDE ships with tsc
built-in? That’s right—it’s VS Code, baby 😎. All I needed was a bit of configuration, and I had hover tooltips, inferred types, and more.
You can enable type checking in one of two ways:
Option 1: Per-file opt-in
Add this comment to the top of your JavaScript file:
// @ts-check
Option 2: Project-wide config
Create a jsconfig.json
in your root directory:
{
"compilerOptions": {
"checkJs": true
}
}
From there, I got greedy. Why stop at types? Why not get red squigglies too—without a build step? Enter: ESLint. By pairing ESLint with a JSDoc plugin and some well-chosen rules, I finally had my perfect squiggle setup.
I’ll cover the ESLint setup in another post—let me know if you’re interested!
Once I had ESLint checking my JSDoc annotations, I was off to the races. I immediately caught three or four real bugs that had slipped through earlier. Type checking was back. Dev workflow restored. No build step required.
JSDoc, here to save the day. Until next time 👋🏽 🫡
Nice article, Jordan! I noticed it because it got picked up by this week’s JS Weekly. And, yes, I would be interested in seeing a follow-up article on those ESLint setup tweaks. :-)
Thanks Bob! Thank you for letting me know, I had no idea! That’s super cool. I’ll keep you in loop for when I write the ESLint follow up 🫡
Hi, Jordan! I created JSDoc 25 years ago, intended only as a documentation tool, but like you I find now that pairing it with VSCode and ESLint makes for the perfect type safety tool set—when TypeScript isn’t an option. Your article describes that use case perfectly! Thank you for sharing.
Hey Michael! And woah 🤩 first off – thank you for making such a cool tool. I’m stoked to hear that I was on the right track pulling it. For me it was the perfect tool for the job and the dev experience was great. JSDoc has a permanent place in my tool belt.
What do you need ESLint for? Just use jsconfig.json + checkJs: https://www.typescriptlang.org/tsconfig/#checkJs
Thanks for reading! jsconfig.json will give you type checking however pairing that with ESLint helps supercharge collaboration. ESLint enforces coding standards, helps avoid bugs, and ensures code consistency.
Great post! We’ve been using similar tricks when client teams push back on TypeScript. Your “TypeScript isn’t an option” example really hits home. I’ve dealt with clients stuck on legacy build rules they can’t change, and they have to ship features before they can carve out the time to upgrade.
Catching real bugs right after setup shows just how powerful this is. I’m excited for your ESLint setup guide and some practical config examples.
Hey Colin! Thanks for sharing. I’m with you, we don’t build in a vacuum. It was a handy tool.
I know right! Catching bugs immediately after setup was all the confirmation I needed that we needed to pull it in. I’ll keep you in the loop for when I write the ESLint post 🫡