Jsdoc Is Typescript
Key topics
Sparks ignite in a fiery debate over whether JSDoc is secretly just TypeScript in disguise, with the author insisting that its squiggly lines and IntelliSense magic all stem from TypeScript's language services. Purists push back hard, calling it a mere comment standard parsed by independent tools—like distinguishing ISO C++ from GNU C++—while pragmatists nod along, noting that in today's ecosystem, JSDoc invariably leans on TypeScript for real-world power. Counterpoints highlight quirks like uncontrollable type exports in JSDoc, yet fans rave about its build-step-free bliss for web components, underscoring why this tooling tussle captivates JS devs amid the endless quest for frictionless typing.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
1h
Peak period
107
0-6h
Avg / period
12.3
Based on 160 loaded comments
Key moments
- 01Story posted
Dec 14, 2025 at 2:42 PM EST
21 days ago
Step 01 - 02First comment
Dec 14, 2025 at 4:01 PM EST
1h after posting
Step 02 - 03Peak activity
107 comments in 0-6h
Hottest window of the conversation
Step 03 - 04Latest activity
Dec 18, 2025 at 11:38 AM EST
17 days ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
As I pointed out in the article, the "tooling" is exactly TypeScript language services. If you are using JSDoc and you get squigglies or intellisense or any other similar features, you are using TypeScript.
You can copy-paste basically any bit of TypeScript into a JSDoc comment and it will work. JSDoc supports any non-runtime feature of TypeScript (so not enums). Even generics! You can even reference TypeScript utility types!
The whole point of this article was to correct the idea that JSDoc is not TypeScript. It absolutely is! There's almost nothing you can't define in JSDoc that you can't define in a .ts file. Albeit with a sometimes clunkier syntax
JSDoc is a comment formatting standard.
The tooling used to parse it is independent.
In the same vein, a file of ISO C++ (take any version) code is not "GNU C++".
Just because currently the most popular method for parsing JSDoc utilizes TypeScript-related tooling doesn't mean we should associate them with each other.
To my previous example, an ISO C++ can be compiled by GCC but also can be compiled by Clang (and many other compilers).
This is true in the same way you are "using" C++ if you are on Windows. When most people say "use XYZ language" they mean "are personally writing code in XYZ language" rather than "under the hood my code is transpiled to this other language I don't write in"
It might not have been so originally. It might still be possible to do differently. But in practice today you are getting Typescript in your JSDoc with the out of the box tooling that is everywhere.
No of course not, that's an absolutely ridiculous thing to say. Just because cats have four legs doesn't mean things with four legs can be "different kinds of cats", ∀A -> B does not imply ∀B -> A, it only means ∃B -> A.
Thinking about "still cats, just different kinds of cat" means you completely missed the point: what else has four legs? Dogs, or deer, or bears, but wait, there's more! What about tables or depending on how they're built, ladders? All valid. None of them even remotely related to cats.
What people _could_ be doing vs what they _are_ doing was explicitly my point, so please stop pretending it wasn't, less we have to repeat this merry go round.
For another analogy, I could say that "In principle, char in C isn't guaranteed to be 8 bits, but in practice these days, you will never work on a platform without an 8-bit char type."
A good rebuttal would be to offer some examples of modern JSDoc tooling that is incompatible with TypeScript syntax.
If you define a type in a file with @typedef, it is automatically exported and there is nothing you can do to control that: https://github.com/microsoft/TypeScript/issues/46011
I tried making a library this way and lacking control over the visibility of the exported types was really painful; it made my intellisense awful because every type I defined at the root was exported from the library
Once we get it, there is still a solid decade before runtimes support it, and optimistically, still more 10 years minimum having to deal with an interpreted language that has acquired an unecessary build step.
I absolutely hated when PHP switched from a phpDoc culture with static analysis (and IDE inconsistencies that would click-take you to stubs as well) to actual types. Not because I hate types, but because of the transition period. Once it's gone, it's such a relief to get rid of unecessary docblocks.
I'm currently in the process of trying to pull together our first big release.
Also, comments are syntax and they're mostly meaningless. By your reasoning, programming languages should have no comments.
So, it's not really a qualitative issue (presence of meaningless syntax) but a quantitative one (presence of lots of parsing complexity).
Look, I understand the purism and mostly, I agree. But this is not a clean slate language, it will never be perfect and it's going to become more and more idiosyncratic as times go by.
Comments are a kind of freedom in code. You're completely free to use them precisely because (in a plain execution environment) they cannot ever influence the result of evaluation
If comments /can/ change the result of evaluation then you simply are not free to use them.
It's miserable having a de-facto build step for an interpreted language. Worst of both worlds.
Maybe just TS is fast, but it encourages developers to put more and more stuff into that build step (and they do, they do that a lot). Culturally, that trend is not going to change unless the main reason for having said build step is removed.
The whole babel/transpiling thing was meant to be temporary. It became temporarily permanent / permanently temporary.
ok i didn't think about this, that's an underrated benefit
IDEA adds its own analysis on top of that provided by the language server.
Works on JS + every variant of type definitions I've ever seen, among many other things (not only programming languages, but also database objects, etc).
It was added like 3 years ago which was probably a bit too late, not even sure why it's not the default. (File size?)
You should occasionally look at the build artifacts of your framework but also ask yourself whether it is worth it to write code that may not represent what actually ends up being executed.
Lately I just use vite with no starter template but with web components and css modules. It at least feels more convenient than using any framework or library.
And I don't know about you, but I occasionally do open compiled ELF files in a hex editor and I certainly did at first when I was learning more. That's a good practice also.
I think the point I'm trying to make is that this can be confusing or even dangerous especially for new developers. It just doesn't hurt to actually look at the Vite plugins transforming it all to understand it instead of making assumptions if we work with it on the daily.
(asking to learn)
I've even used Proxies directly to implement some reactivity before. However as for the "declarative" parts, I think it's just a little bit of a different way to work but you get used to it and imo it pays off. Knowing the web APIs should be a requirement anyway and it doesn't hurt to work with them directly as much as possible.
Occasionally, I have to remember that JavaScript has no types at runtime but it's surprisingly not that often.
However I have been in a few situations at work where all of a sudden we did have dog deeper. There were also some bundling related issues that caused issues in production deployments. At that point many co workers had no idea how to even approach it to be honest.
Then, paradoxically, with no error checking at runtime, it becomes fully possible for JS code to call into TS code in a way that breaks the shit out of the TS compiler's assumptions. In philosophy then TS and JS are as incompatible as GPL and EULA
To bridge runtime and compile time (as your application will likely get some external data) you've got to use a proper parser such as zod[1] or if you want to stretch it even further effect-schema[2].
[1] https://zod.dev/
[2] https://effect.website/docs/schema/introduction/
https://arktype.io/
However, if your point is that Typescript can lull people into a false sense of safety, then sure, I take your point. You have to understand where type assertions are coming into play, and if that's obscured then the type safety can be illusory. The benefits of Typescript require you to make sure that the runtime inputs to your program are sufficiently validated.
Usually there's little if any protection against a JS caller providing wrong-type args to TS functions.
* I'm aware that you can't run Typescript directly, but I hope my point here is clear... you're running a program that wasn't type-checked by TS.
If you write a C library, nothing stops someone from writing an assembly-language program that calls functions in your library with the wrong types.
If it's a service, yes, and that's true no matter what technology the service is using. If it's a library, no, because...
> and if you write type assertions without ensuring that the assertions are accurate, then that's on you, not Typescript.
That's on whoever is using the library, not the library author. If the library author provides type definitions, and you as the consumer choose to ignore them, then it's on you.
Sure, you can check if they gave you a string instead of a number. But if you receive an array of nested objects, are you going to traverse the whole graph and check every property? If the caller gives you a callback, do you check if it returns the correct value? If that callback itself returns a function, do you check that function's return type too? And will you check these things at every single function boundary?
This kind of paranoid type-checking would completely dominate the code, and nobody does it. All you can do is offer a type-safe interface, trust your callers to respect it, and check for a few common mistakes at runtime. You cannot protect your code against other code calling it incorrectly, and in practice nobody does.
I vividly remember being in a meeting with the Exchange team (about building shared frontend components) arguing for us to adopt TS instead as it had a better experience and very rapidly growing popularity (that was about 10 years ago). Plus, as strong as Nikhil [0] was, he was basically the only person behind ScriptSharp while TS had a whole team.
Of course, this being MSFT, this effort went no where. While true that the TS toolchain lacked the tree-shaking that ScriptSharp had, I was just annoyed that we had to build stuff using what was obviously an dead-ish language with limited support, may flaws, and no resources to improve it.
But hey, at least it wasn’t GWT.
[0] https://github.com/nikhilk
However, the precision and completeness is not nearly what can be expressed in TypeScript. With generics particularly.
The clunkiest part is in the way you "pass in" a generic to a slot. But this is solved by typing the return type.
I use generics pretty extensively and I've not yet come across a use-case JSDoc couldn't handle
[0] https://news.ycombinator.com/item?id=46267810
Which is a lot different than vanilla JSDoc [1].
I understand.
[1] https://jsdoc.app/
Almost any modern IDE is also parsing JSDoc comments through the TypeScript language service. So many people don't realize they are already using TypeScript (hence the name of this post).
I don't think it's particularly controversial to say that the form of JSDoc that the majority of developers are familiar with IS JSDoc. The distinction is more of a historical one than a technical one (since there is no formal JSDoc spec)
2. you can have navigation that goes to typescript file instead of definition, just arrange your exports in package.json correctly (first ones take precedence)
This isn't really true anymore, they have systematically added pretty much every type system feature to the JSDoc-like syntax.
You keep repeating this throughout the thread. Can you give an example?
export type SemVer = `${number}.${number}.${number}`;
Could you extend it to work with regex groups like:
export const SemVerRegex = /^(?<major>0|[1-9]\d)\.(?<minor>0|[1-9]\d)\.(?<patch>0|[1-9]\d)(?:-((?:0|[1-9]\d|\d[a-zA-Z-][0-9a-zA-Z-])(?:\.(?:0|[1-9]\d|\d[a-zA-Z-][0-9a-zA-Z-]))))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
Could the groups be extracted so you the type back if you ran the regex on a string like: "1.2.3", or "1.2.3-prerelease"?
The second part of my comment is a value yes, but it's implicitly typed by typescript automatically. I was asking about how to use that type (and it's internals) in jsdoc.
`test()` only returns a boolean, you want to look at `exec()` which returns the result of the regular expression (typed as: `RegExpExecArray | null` which you can narrow down to `RegExpExecArray` by checking if the result is null or not).
RegExpExecArray gives you a structure that looks different between the jsdoc version and the typescript version.
The typescript version has `.groups` inside RegExpExecArray.
You can use that as is, or you can add some extra type utilities to extract the named groups from inside the regex. (If you look inside typescript's issues on github you'll find a whole bunch of them that people have wanted typescript to include by default).
There's a few regex PRs to add extraction and syntax checking to typescript by default, but they're delayed until after the compiler switch from ts to go. (but there's porting to go in the PRs anyway).
Since any TypeScript type can be expressed in JSDoc, I imagine you're mostly thinking of generics. At least that was my main sticking point. JSDoc does actually have generic slots with the @template tag. Actually using them in practice is a little unintuitive but involves typing the return type. E.g. for a function it'd look like this:
second it's not a solution - for .d.ts types to be available globally without explicit import the .d.ts file itself cannot use any imports/exports. this means you can't reuse types from other places to construct your types. you can workaround this by explicitly importing .d.ts in jsconfig/tsconfig but you're still left with other issues.
those types do actually become globally visible everywhere (polluting global namespace is bad in itself), there are no guarantees about them being in sync with actual code (which violates the whole point of using type safety) and they don't solve cases where you need typescript inlined functionality locally in your code or to perform assertion with satisfies operator etc.
TypeScript utility types are available in JS. You can pretty much copy-paste any typescript Type/Interface into JSDoc
JSDoc also allows you to type stuff in-line. For example I often have to type an empty array like so:
If you have a tangible example of a problem you've run into, I'd love to walk through it.https://www.typescriptlang.org/play/?filetype=js#code/PTAEAE...
Almost equivalent typescript code:
https://www.typescriptlang.org/play/?#code/C4TwDgpgBA6glsAFg...
(I had to make it a little bit different from the JS code to make it compile)
Note that I cannot make the type check in JS code to pass. Whatever I do, there is always a error. Meanwhile, it does not take much to TS code to work.
https://www.typescriptlang.org/play/?filetype=js#code/PTAEAE...
Hover over the variables and you should see that the type inference is working just the same as in your TypeScript example
I do think it illustrates a problem with TypeScript's support for JSDoc though. You see, I started with the code in JS and could not make it work, after which I translated it to TS. In JS/JSdoc, "@callback" is the "idiomatic" way of defining a function callback type with JSDoc. (It also makes it easier to add documentation for each parameter if necessary.) And indeed, @callback works the most of the time, except in such cases where these JSDoc tags don't work nicely together, and these alternatives become necessary.
My brain definitely works in TypeScript so I tend to translate from there. I definitely consider myself more familiar with TypeScript than with JSDoc, but sometimes (e.g. here) that's a benefit not a weakness
Also if you're curious about the equivalent of `extends` in generic slots, here's an example I have from a different project
The generic slot here, T, is "extended" by Record<string, unknown>. The equivalent in TypeScript would look likeEveryone's complaining about "the build step" but the build step is just an eye blink of stripping out some things that match a regex.
This is inaccurate on multiple counts. First of all, you can still run tsc with JSDoc if you want a hard error and you can still use strict mode with JSDoc. Your tsconfig file governs JSDoc-typed code just the same as it governs .ts-typed code. In both cases you can also ignore the red squigglies (the exact same red squigglies) and end up with runtime errors.
Nobody is advocating for reduced type safety or increased runtime errors.
I also think there are many valid reasons to loathe a build step (like not dealing with the headache that is the discrepency between the way the TS compiler deals with import paths vs js runtimes).
All that being said, I'm not really trying to convince anyone to stop using TypeScript. I'm simply pointing out that using JSDoc is using TypeScript. It's the same language service.
All non erasable constructs won't work as well of course but playing devil's advocate you could explicitly state that you're interested in erasable constructs only because ie. 1) that's what typescript should be doing from day 1 and/or 2) it seem to be the future with ie. nodejs adopting built in type erasure support.
When other developers and non-developers look at JavaScript developers as small children it’s because the maturity difference is very evident from the outside. Once developers get past basic literacy they are free to worry about architecture, performance, scale, platform independence, and more. For most JavaScript developers they just expect some framework to do it for them.
I choose to use it because I didn't want to deal with a build step for a smaller project. The project has grown and I am looking at adding a build step but using JSDoc over TS isn't that bad IMO.
----------------------
Here's an example - I got some config typed with this function https://github.com/AKST/analysis-notebook/blob/c9fea8b465317... - Here's the type https://github.com/AKST/analysis-notebook/blob/c9fea8b465317... - And here's something to generate a more complicated type for defining config knobs https://github.com/AKST/analysis-notebook/blob/c9fea8b465317...
https://akst.io/vis/20250601-complex-geo/?app=unsw.2102.01-1
That said, when I write tests, I write them in Typescript for that reason.
https://github.com/tc39/proposal-type-annotations?tab=readme...
Also, it's not a super limited subset. For instance, you can write types in .d.ts the IDE uses those types in jsdoc out of the box.
https://devblogs.microsoft.com/typescript/announcing-typescr...
But not properly documented (https://www.typescriptlang.org/docs/handbook/jsdoc-supported...), which shows how much Microsoft neglects JS + JSDoc workflow. Github issues have been created a long time ago, but nothing has been done so far. Apparently Microsoft is too busy with their AI slop to work on actually useful stuff.
1. not having to type everything (many types are not helpful)
2. makes code less dense (and they can be rendered in HTML) https://x.com/efortis/status/1989776568676221137
3. not needing a compiler (browsers don't support TS)
I think the main jsdoc caveat is around private types.
About 1, IDK if there’s a way to set up TS for that.
But JSDoc lets you do pretty much everything that isn't a runtime feature of TypeScript (e.g. enums, namespaces, etc). Even generic slots are supported
I found several limitations and already opened several issues on github.
Also, in WebStorm, jsdoc can be rendered in HTML, which makes the code easier to scan. Here's a side-by-side VSCode vs WebStorm:
https://x.com/efortis/status/1989776568676221137
This entirely depends on your tsconfig setup. You can run a JSDoc-typed project in strict mode exactly the same way you would a *.ts-typed project.
https://jsdoc.app/tags-deprecated
Modern HTML/CSS with Web Components and JSDoc is underrated. Not for everyone but should be more in the running for a modern frontend stack than it is.
Do you have anything specific in mind?
Any kind of downleveling, though that's less important these days most users only need polyfills, new syntax features like `using` are not widely used.
Minification, and bundling for web is still somewhat necessary. ESM is still tricky to use without assistance.
None of these are necessary. But if you use any of them you've already committed to having a build step, so adding in a typescript-erasure step isn't much extra work.
No Lit Element or Lit or whatever it's branded now, no framework just vanilla web components, lit-html in a render() method, class properties for reactivity, JSDoc for opt-in typing, using it where it makes sense but not junking up the code base where it's not needed...
No build step, no bundles, most things stay in light dom, so just normal CSS, no source maps, transpiling or wasted hours with framework version churn...
Such a wonderful and relaxing way to do modern web development.
- signals, which is currently Stage 1 https://github.com/tc39/proposal-signals
- And this proposal: https://github.com/WICG/webcomponents/issues/1069 which is basically lit-html in the browser
https://github.com/Vorticode/solarite
Try my tiny web components lib if you want to keep JSX but not the rest of React: https://github.com/webjsx/magic-loop
It's not a no-build option though.
Code written for a web browser 30 years ago will still run in a web browser today. But what guarantee does a build step have that the toolchain will still even exist 30 years from now?
And because modern HTML/CSS is powerful and improving at a rapid clip. I don't want to be stuck on non-standard frameworks when the rest of the world moves on to better and better standards.
Will it? - My browser doesn't have document.layers (Netscape) It seems to still have document.all (MSIE), but not sure it's 100% compatible to all the shenanigans from the pre-DOM times as it's now mapped to DOM elements.
https://www.spacejam.com/1996/
Those were both vendor-specific, neither were part of the w3c. I don't recommend ever writing vendor-specific code.
The w3c and standards have generally won so it's easier than ever to write to the standard.
Especially helpful as applications become larger and a debugger becomes necessary to efficiently track down and fix problems.
Granted they initially weren't down that path, but they course corrected it on time, and not much people use stuff like enums in new code.
108 more comments available on Hacker News