We use cookies
To improve your experience. Cookie policy
Engineering
TypeScript has won the adoption war, but for certain project profiles, a disciplined JSDoc approach gives you 80% of the safety with zero build-step overhead and full IDE intelligence.
Callum Ashby
Principal Engineer
Let's get the obvious out of the way: TypeScript is excellent. For large teams, long-lived codebases, and libraries that need to publish types, it's frequently the right call. But the JS ecosystem has quietly shipped something underappreciated — modern JSDoc, combined with TypeScript's own type-checking engine, gives you declaration files, IDE autocomplete, and tsc --noEmit validation without ever writing a .ts file.
A build step isn't free. Every CI run pays for transpilation. Every developer pays for the occasional Cannot find module or Type 'X' is not assignable to type 'Y' rabbit hole on a refactor. For well-staffed product teams with TypeScript expertise, this is a worthwhile trade. For a lean agency building client projects at speed, the calculus shifts.
checkJs gives youWith checkJs: true and allowJs: true in your tsconfig.json, VS Code and tsc validate your JavaScript with the same engine that powers TypeScript. @typedef gives you structural typing. @param, @returns, and @template give you generics and documentation simultaneously. @type {import('./types').MyType} gives you cross-file type imports.
/**
* @param {{ name: string; email: string }} user
* @returns {Promise<{ id: string }>}
*/
async function createUser(user) {
const res = await db.users.create({ data: user });
return { id: res.id };
}
The function above is fully type-checked in VS Code. Rename email in the typedef — the call sites light up red. This isn't "weak typing" — it's TypeScript's inference engine, pointed at plain JavaScript.
You lose: declaration files for library consumers, some advanced mapped/conditional types, and decorator support. You gain: zero build complexity, onboarding of developers unfamiliar with TypeScript, and the ability to run your code directly in Node.js without ts-node or tsx.
For internal tooling, client projects where the client owns the codebase long-term, and Next.js applications where the framework handles the build anyway — JSDoc is a legitimate and underrated choice.
In your jsconfig.json or tsconfig.json: checkJs: true, strict: true, noImplicitAny: true. Install @types/node and any @types/* packages you need — they work transparently with JavaScript. Run tsc --noEmit in CI alongside your tests. You now have type safety without a transpilation step.

Written by
Callum Ashby
Principal Engineer
Callum has been shipping JavaScript since Node.js 0.10. He leads engineering standards at stackloader, with a focus on developer experience, type safety, and build performance. He believes the best tool is often the one with the fewest moving parts.
More from the blog
Newsletter
New articles on AI, DevOps, and engineering craft. Roughly twice a month. No noise, no promotions — just the good stuff.