JSDoc is TypeScript
Posted by culi 2 days ago
Comments
Comment by Waterluvian 2 days ago
- The types exist whether you write them down or not.
- If they're not written down, they're written down in your head.
- Your head is very volatile and hard for others to access.
- Typing is an incredibly good form of documentation.
- JSDoc and TypeScript are standards/formats for typing. Like any tools, they both have advantages and disadvantages. Neither is objectively better than the other.
- Make informed decisions on how you'll describe your types, and then be consistent and unsurprising.
- A type checker is the computer saying, "okay then, prove it" about your program's type validity.
- Not every program benefits from the same amount of "prove it."
- Too much can be as bad as too little. You're wasting resources proving throwaway code.
- I like languages that let you decide how much you need to "prove it."
Comment by Culonavirus 1 day ago
One of the lessons you learn while doing this job is that "others" includes "yourself in the future".
(Of course people will tell you this way before you find out yourself, but what do they know...)
Comment by have_faith 1 day ago
Comment by pavel_lishin 1 day ago
Comment by john01dav 2 days ago
Rust is known for being very "prove it," as you put it, but I think that it is not, and it exposes a weakness in your perspective here. In particular, Rust lets you be lax about types (Any) or other proved constraints (borrow checker bypass by unsafe, Arc, or cloning), but it forces you to decide how the unproven constraints are handled (ranging from undefined behavior to doing what you probably want with performance trade-offs). A langauge that simply lets you not prove it still must choose one of these approaches to run, but you will be less aware of what is chosen and unable to pick the right one for your use case. Writing something with, for example, Arc, .clone(), or Any is almost as easy as writing it in something like Python at the start (just arbitrarily pick one approach and go with it), but you get the aforementioned advantages and it scales better (the reader can instantly see (instead of dredging through the code to try to figure it out) "oh, this could be any type" or "oh, this is taken by ownership, so no spooky action at a distance is likely").
Comment by MrJohz 1 day ago
The same is true at multiple levels. `.clone()` is relatively easy to use, although once you learn the basic rules for referencing, that also becomes easier. `Arc` solves a specific problem you run into at a certain point sharing data between threads, but if you're not sharing data between threads (and most of the time you're not), it's just boilerplate and confusing, so you might avoid it and at worst use `Rc`. `Any` is rarely an obvious choice for most contexts, you really are going to only use it when you need it.
The result is that for most simple cases, the precise and "proven" option is typically the easiest to go for. When you deal with more complicated things, the more complicated tools are available to you. That seems exactly what the previous poster described, where you can decide yourself how much you need to prove a given thing.
Comment by throawayonthe 1 day ago
Comment by culi 2 days ago
Agreed. Just to clarify, my intentions with this post weren't to advocate for one over the other. Just to point out that they are the same thing. They are both TypeScript.
Comment by mattmanser 1 day ago
"Like any tools, they both have advantages and disadvantages"
You cannot make any argument based on such a position. Putting aside anyone's views on TS or JSDoc, tooling is of extremely variable quality, and lots of tools ARE objectively much worse than other tools.
It we can't point at tools and say this one is better than that one, we might as well give up.
I always remember a scene in Will & Grace where Will is trying to get his boss to say one thing is better than the other. He's brought a lovingly hand-crafted sandwich made with amazing, bread, fillings, etc. and a store bought sandwich made with cheap bread/fillings. He asks his boss to try both and say which one he likes more.
His boss says something like the store bought one reminds him of his grandma's sandwiches, so invokes nostalgia, and still can't make a decision.
Don't be that boss.
Comment by rpsw 1 day ago
Or is you problem with the word any instead of many?
Comment by KPGv2 1 day ago
I take issue with this position because this seems to imply "PureScript and JavaScript are both JavaScript" is a true statement merely because one of them turns into the other with tooling.
Comment by nosianu 1 day ago
TS does have some minor things like enums that need to be transformed and are actual code, but those are very few, and leftovers from early days of TS, and the TS authors regret having implemented them. For many years now the TS philosophy has been that the CODE part of TS is 100% ECMAscript, and only annotations, which are not code, are added.
The initial Babel transpiler for TS => JS, and still the most part of the current one, simply removes annotations.
It is recommended not to use the few parts that are actual code and not standard JS. They are certainly not needed any more since ES6.
People may get confused because the type syntax itself is almost like a programming language, with conditions and all. But none of that ends up as code, it's not used at runtime.
One of the IMHO worst design decisions of TS was to bundle type checking and transpiling into one tool. That caused sooo many misunderstandings and confusion.
Comment by egeozcan 1 day ago
Comment by aatd86 1 day ago
TS from JSDoc requires a generative pass to. This is a (expected) level of indirection. (unless some tooling does it automatically)
Comment by jama211 1 day ago
Comment by jve 1 day ago
I don't get it. Types are a way to write code. Nothing to do with how fast/much the code changes.
Comment by jama211 9 hours ago
Comment by scotty79 1 day ago
Comment by skydhash 1 day ago
Comment by embedding-shape 1 day ago
This is true, but with a program built with a dynamic language, taking advantage of the fact that it's written in a dynamic language, doesn't need to make those changes at all.
I'm fan of static typing in many situations, but it's hard to deny it doesn't lead to more changes as you need to properly propagate changes.
Comment by ARandumGuy 1 day ago
If I change the shape of some data (such as renaming object properties), I'll need to update all the code that used that data, regardless of the type system. Static typing just ensures that I catch those cases at compile time, not runtime.
Comment by embedding-shape 1 day ago
JavaScript:
// rename host -> hostname, update ONE place
function connect(opts) {
const host = opts.hostname ?? opts.host; // compat shim
return `tcp://${host}:${opts.port}`;
}
// old call sites keep working
connect({ host: "db", port: 5432 });
connect({ host: "cache", port: 6379 });
// new call sites also work
connect({ hostname: "db", port: 5432 });
TypeScript: // same compat goal, but types force propagation unless you widen them
type Opts = { port: number } & ({ host: string } | { hostname: string });
function connect(opts: Opts) {
const host = "hostname" in opts ? opts.hostname : opts.host;
return `tcp://${host}:${opts.port}`;
}
// If instead you "just rename" the type to {hostname; port},
// EVERY call site using {host; port} becomes a compile error.
Again, this is just a simple example. But multiply 100x + way messier codebases where everything are static types and intrinsically linked with each other, and every change becomes "change -> compile and see next spot to change -> change" until you've worked through 10s of files, instead of just changing it in one place.Personally, I prefer to spend the extra time I get from dynamic languages to write proper unit tests that can actually ensure the absence of specific logic bugs, rather than further ossifying the architecture with static types while changes are still ongoing.
Comment by ARandumGuy 1 day ago
> Personally, I prefer to spend the extra time I get from dynamic languages to write proper unit tests that can actually ensure the absence of specific logic bugs, rather than further ossifying the architecture with static types while changes are still ongoing.
I'd argue static typing makes this much easier, because I know any input types (or output types from other components) will be enforced by the type system. So I don't need to bother writing tests for "what if this parameter isn't set" or "what if this function returns something unexpected". The type system handles all of that, which eliminated a lot of tedious boilerplate tests.
Comment by embedding-shape 1 day ago
Yeah, sure, and with LLMs you can do this, and you can do that. But if we're talking about languages and their features, relying on IDE features feels slightly off-topic.
But regardless, changes is changes, no matter if you, your IDE or your LLM made them. So even if your IDE makes the changes, it seems at least you can now agree that there are more changes needed, it's just that with TypeScript you have a editor who can help you refactor, and with JavaScript you haven't yet found an editor that can do so.
> So I don't need to bother writing tests for "what if this parameter isn't set" or "what if this function returns something unexpected".
Yeah, those unit tests does nothing, and people who write in dynamic languages don't write tests like that either. You test actual logic, in unit tests, and you rely on the signals that gives you.
In fact, I could bet you that if you and me both sat down and wrote the exact same application, one in JS and one in TS, we'd end up with more or less the same amount of unit tests, yet the JS codebase will be a lot more flexible once product requirements start to change.
But again, YMMV and all that, it's a highly personal preference. I don't think there is a ground truth here, different minds seem to prefer different things. I mostly work in environments where the requirements can change from day to day, and being able to adopt to those without introducing new issues is the most important thing for me, so with JS I stay.
Comment by ARandumGuy 1 day ago
Refacoring tools (such as renaming properties) have been supported by IDEs for decades. And in Typescript specifically, the language is designed with these tools in mind, which are developed and distributed directly by the Typescript team. For all intents and purposes, IDE integration using the Typescript language server is a feature of Typescript.
And if somehow these tools don't work, the compiler will catch it immediately! This means I can refactor with confidence, knowing any type issues will be caught automatically.
It seems like you're vastly overestimating the time and effort it takes to change types in Typescript. In my experience it's something that takes basically no time and effort, and has never caused me any issues or headaches.
Comment by embedding-shape 1 day ago
I'm not saying it's hard to change types in TypeScript, I understand that your IDE is connected with the language and they're used together, but again my argument was that having types leads to having to change things in more places. Which is true too, and it's a good thing, it's on purpose, and the tools you use help with that, so yay for that! But it's still more changes, and at least for me it's important to be honest about the tradeoffs our choices leads us to.
As I mentioned earlier, I'm fan of static typing in many situations, just not all of them. And I'm not blind to the negatives they can bring too, I guess I just see more nuance in the static typing vs dynamic debate.
Comment by skydhash 1 day ago
Comment by scotty79 1 day ago
No, because if a piece of data is pushed through multiple layers you can just change its type at the source and the destination and not in all the layers the data is pushed through. And you can still be correct.
Imagine you have a thing called target which is a description of some endpoint. You can start with just a string, but at one point decide that instead of string you'd prefer object of a class. In dynamic language you just change the place where it originates and the place where it's used. You don't need to change any spot in 3 layers that just forearded target because they were never forced assumed it's a string.
You can achieve that in staticly typed language if you never use primitive types in your parametrs and return types or if you heavily use generics on everything, but it's not how most people write code.
Tools can help you with the changes, but such refactors aren't usually available in free tools. At least they weren't before LLMs. So the best they could do for most people was to take them on a journey through 3 layers to have them make manual change from string to Target at every spot.
Comment by skydhash 1 day ago
fn split(str: string) => string[]
And you called it withconst first_el = split(target)[0]
If you decide `target` to suddenly be an object, then the code you wrote is incorrect, because semantically, `split` only makes sense when the argument is a string. Which is why, even with dynamic typing, you'll see that the documentation of a function will state what kind of parameters it expects.
If you a call chain like `fn1 | fn2 | fn3 | fn4 | split`, Then yeah you need to ensure what reaches `split` is in fact a string. If you're against updating fn[1-4]'s signature, let's say that it's harder to find which function needs to change in a dynamic typing systems.
Dynamic typing is useful for small programs and scripts because they are easy to iterate upon. But for longer programs, I'll take static typing anytime.
Comment by scotty79 15 hours ago
While I always liked dynamic languages and probably wrote most of my code in them I don't think they are useful anymore. Tooling got great and LLMs need every chance they get of verifying stuff they hallucinated. At this point I wouldn't mind a language that's strict about typing but other things as well as ownership, protocols, mandatory assertions, tests, code coverage, even some formal verification. As long as I don't have to write them, but LLM does and uses them to check its work, I'm really fond of it.
Comment by scotty79 1 day ago
Comment by christophilus 1 day ago
Comment by dominicrose 1 day ago
That's easy to say when we're talking about primitive arguments in private functions, or primitive local variables, but let's not ignore the fact that it takes much more work to write a C# program than a Ruby program for instance.
We can see that by looking at a vanillajs library's typescript typings that were created after the js library when typescript didn't exist. The types are insanely complex and if you get one type wrong you can break compilation of some library user's program (its happened to me).
That being said I'm aware that dynamic programming languages are a "use at your own risk" type of language.
Comment by dzonga 1 day ago
my take is if you treat your program as a series of data flows - then use primitives such as maps | arrays - then you don't need as much typing or typing at all. a map doesn't need to take a shape or a Person | Manager - either the keys exist or they don't and almost every language has guards to ensure you can safely navigate existence of keys.
but then again my realm is mostly around - web | data systems - if I was dealing with OS level systems and needed to make sure i have i64 ints then yeah typing would be crucial.
Comment by dominicrose 14 hours ago
Comment by scotty79 1 day ago
I love that too. Are there any other languages than TS that have this as a core design feature?
Comment by jve 1 day ago
Comment by matt_kantor 1 day ago
Comment by scotty79 1 day ago
I can't just write C++ like:
any a = 1;
a = "Hi!";
I also can't tell JS this shouldn't be allowed. But I can tell this to TS, at any stage of evolution of my program.Comment by fulafel 21 hours ago
In this case you'd need to be pretty explicit about the bypassing but you could write
int a = 1;
strcpy((char *)&a, "hi");
(and it'll even kind of work in this instance since "hi" fits in an int, if on your C/C++ implemnentation int happens to be sized 3 bytes or more)Comment by user3939382 2 days ago
Comment by prisenco 2 days ago
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.
Comment by bobbylarrybobby 2 days ago
Comment by prisenco 2 days ago
Do you have anything specific in mind?
Comment by webstrand 2 days ago
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.
Comment by brazukadev 2 days ago
Comment by claytongulick 2 days ago
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.
Comment by prisenco 2 days ago
Comment by brazukadev 2 days ago
Comment by Calazon 1 day ago
Comment by odie5533 2 days ago
Comment by prisenco 2 days ago
Seriously, start a project and use only the standards. You'll be surprised how good the experience can be.
Comment by junon 2 days ago
Comment by WorldMaker 11 hours ago
Comment by eric-p7 2 days ago
Comment by jeswin 2 days ago
Try my tiny web components lib if you want to keep JSX but not the rest of React: https://github.com/webjsx/magic-loop
Comment by prisenco 2 days ago
Comment by brazukadev 2 days ago
- 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
Comment by junon 1 day ago
Comment by gedy 1 day ago
It's not a no-build option though.
Comment by auxiliarymoose 2 days ago
Especially helpful as applications become larger and a debugger becomes necessary to efficiently track down and fix problems.
Comment by mb2100 1 day ago
Comment by winrid 2 days ago
Comment by fergie 1 day ago
I've been a front end developer for 25 years. This is also my opinion.
Comment by pjmlp 1 day ago
However I don't get to dictate fashion in developer stacks.
Comment by mmcnl 1 day ago
Comment by prisenco 1 day ago
Comment by mmcromp 2 days ago
Comment by prisenco 2 days ago
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.
Comment by johannes1234321 1 day ago
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.
Comment by prisenco 1 day ago
https://www.spacejam.com/1996/
Those (document.layers and document.all) 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.
Comment by xigoi 1 day ago
Comment by kellengreen 1 day ago
Comment by etoxin 2 days ago
Then Google Closure Compiler came along which added type safety via JSDOC and TS came along with (TS)JSDoc support and it's own TS syntax.
The community chose native TS and Google Closure compiler slipped away into the background.
So (TS)JSDoc support is a relic from when Microsoft was trying to get market share from Google.
Today in 2025, TS offers so much more than the (TS)JSDoc implementation. Generics, Enums, Utility types, Type Testing in Vitest, typeguards, plus other stuff.
Today I use TS. I also use plain JSDoc for documentation. e.g. @link and @see for docs. Or @deprecated when I'm flagging a method to be removed. @example for a quick look up of how to use a component.
TS and plain JSDoc are both important together. But (TS)JSDoc alone, is a relic of the past.
Comment by culi 2 days ago
This was my main impetus for writing this article. Modern JSDoc uses the TypeScript language service. You can use generics, utility types, typeguards (including the `is` keyword), regex parsing, etc all with just JSDoc.
I used these features extensively (especially generics) in a personal project and managed to do it all in JSDoc.
Comment by apatheticonion 1 day ago
Types for classes are poor and often you'll find yourself creating a `.d.ts` file or `.ts` file to export non trivial types - however the target file doesn't know how to consume them.
Comment by culi 1 day ago
Regardless, I hardly consider that a "missing basic capability"
I don't know what you mean about types for classes being "poor". Types for classes work exactly the same way
Comment by apatheticonion 1 day ago
The alternative is to do an inline `const foo = /** @type {import('./foo').x} */ ({})` however this gets messy, repetitive and it's difficult to use algebraic types (e.g. `Event & { detail: string }`)
Comment by rangedbarbarian 1 day ago
Comment by c-hendricks 2 days ago
https://github.com/jsdoc/jsdoc/issues/1917
https://github.com/jsdoc/jsdoc/issues/1917#issuecomment-1250...
Comment by culi 2 days ago
```js
/**
* @type {{
* slug: `${string}_${number}`;
* id: number;
* } & { status?: [code: number, text: string]; }}
*/
const example = { slug: 'abc_34', id: 34 };
is the exact equivalent of```ts
const example: {
slug: `${string}_${number}`;
id: number;
} & { status?: [code: number, text: string] } = { slug: 'abc_34', id: 34 };
For TS-specific keywords like `satisfies`, there's a corresponding JSDoc keyword like @satisfies. Generics use @template.Is there any specific feature you think is not supported? I'm sure I could work up a TS Playground example.
Comment by c-hendricks 2 days ago
Yeah, uhm, most of what you've been posting? :). That JSDoc example above gives:
ERROR: Unable to parse a tag's type expression for source file /Work/lol-jsdoc-why/index.js in line 1 with tag title "
type" and text "{{ slug: `${string}_${number}`; id: number;} & { status?: [code: number, text: string]; }}": Invalid type expre
ssion "{ slug: `${string}_${number}`; id: number;} & { status?: [code: number, text: string]; }": Expected "!", "$", "'", "(",
"*", ".", "...", "0", "?", "@", "Function", "\"", "\\", "_", "break", "case", "catch", "class", "const", "continue", "debugger",
"default", "delete", "do", "else", "enum", "export", "extends", "false", "finally", "for", "function", "if", "implements", "impor
t", "in", "instanceof", "interface", "let", "new", "null", "package", "private", "protected", "public", "return", "static", "supe
r", "switch", "this", "throw", "true", "try", "typeof", "undefined", "var", "void", "while", "with", "yield", "{", Unicode letter
number, Unicode lowercase letter, Unicode modifier letter, Unicode other letter, Unicode titlecase letter, Unicode uppercase let
ter, or [1-9] but "`" found.
Edit: Also, your first edit says Webpack switched from TypeScript to JavaScript, but Webpack source was never written in TypeScript.Comment by culi 2 days ago
https://www.typescriptlang.org/play/?#code/PQKhCgAIUgBAXAngB...
You are attempting to generate documentation from jsdoc comments using an npm package that is also called "jsdoc". Ofc in this case "JSDoc is not TypeScript". That package only supports the subset of JSDoc that is relevant to it. Though I believe you can use TypeDoc instead if you want to generate documentation from JSDoc that contains typescript types.
In the post I made it explicit that I'm talking about intellisense, developer tooling, type checking etc. You can run `tsc` to do typechecking on a project typed with JSDoc like the examples I've given throughout this thread just fine.
I guess the difference here is I'm coming at this from the perspective of "what is TypeScript used for. Can JSDoc comments substitute that". And the answer is almost completely yes.
Also tbh I've never met anyone that uses that package to generate API docs. I don't think it's a very modern package: https://github.com/jsdoc/jsdoc/issues/2129
Comment by c-hendricks 1 day ago
Your post is actually one of the more accurate ones compared to others that say "you don't need typescript" with the big caveat that you actually need a whole lot of the typescript ecosystem to make JSDoc work.
I just wish there was an official handover, or a more clear delineation between JSDoc and Typescript JSDoc Extensions.
Comment by culi 1 day ago
But given that JSDoc doesn't have any sort of formal spec, I think the distinction you're making is more of a historical than a technical one.
Comment by hsbdhd 1 day ago
JSDoc has been around for more than twenty years and most implementations have never had most of the capabilities you’re describing.
It is actively misleading for you to say that JSDoc has these capabilities when you’re referring specifically and exclusively to TypeScript’s implementation of JSDoc, or you could say TypeScript’s alternative JSDoc syntax. Closure always used language like that in their documentation, and explicitly called out that they had diverged from standard JSDoc, as they should have. TypeScript’s own documentation sometimes refers to it as their superset of JSDoc, again recognizing that “JSDoc” actually does mean something specific and different.
The fact that there may not be a formal technical spec doesn’t mean you’re not wrong and it’s preposterous to suggest that.
There was established tooling and documentation going back 25 years, and it doesn’t somehow not count just because they didn’t give you a formal grammar…
Comment by k3vinw 1 day ago
Comment by culi 1 day ago
Comment by k3vinw 1 day ago
Wishful thinking on my part that an alternative solution for JSDoc based type checking exists :)
Comment by matt_kantor 1 day ago
Comment by k3vinw 1 day ago
Comment by phil294 1 day ago
Comment by johnfn 2 days ago
Comment by phil294 1 day ago
> Today in 2025, TS offers so much more than the (TS)JSDoc implementation. Generics, Enums, Utility types, Type Testing in Vitest, typeguards, plus other stuff.
None of that is true! Please don't share misinformation without looking it up first.
Comment by mirekrusin 2 days ago
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)
Comment by culi 2 days ago
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:
/** @type {ReturnType<typeof useState<Book[]>>} */
const [books, setBooks] = useState();Comment by g947o 2 days ago
Comment by culi 2 days ago
/**
* @typedef {object} Dog @extends Animal
* @property {string} childProp
*/
But I don't really use that feature in TypeScript. Instead I rely on `&`. This works in exactly the same way in JSDoc.Also if you're curious about the equivalent of `extends` in generic slots, here's an example I have from a different project
/**
* @template {Record<string, unknown>} [T=Record<string, unknown>]
* @typedef {{
* children?: NewickNode<T>[];
* name?: string;
* length?: number;
* data?: T;
* }} NewickNode
*/
The generic slot here, T, is "extended" by Record<string, unknown>. The equivalent in TypeScript would look like type NewickNode<T extends Record<string, unknown> = Record<string, unknown>> = {
children?: NewickNode<T>[];
name?: string;
length?: number;
data?: T;
};Comment by llimllib 2 days ago
Comment by KPGv2 1 day ago
Everyone's complaining about "the build step" but the build step is just an eye blink of stripping out some things that match a regex.
Comment by culi 1 day ago
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.
Comment by auxiliarymoose 2 days ago
Comment by g947o 2 days ago
Comment by spoiler 1 day ago
Comment by mirekrusin 1 day ago
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.
Comment by g947o 2 days ago
Comment by culi 2 days ago
JSDoc also allows you to type stuff in-line. For example I often have to type an empty array like so:
const [books, setBooks] = useState(/** @type {Book[]} */([]));
If you have a tangible example of a problem you've run into, I'd love to walk through it.Comment by g947o 2 days ago
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)
(Well, this is not exactly about arrow function I guess. I remembered that part wrong.)
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.
Comment by culi 2 days ago
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
Comment by g947o 2 days ago
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.
Comment by culi 2 days ago
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
Comment by efortis 2 days ago
Comment by mirekrusin 1 day ago
also not a full 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 which 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.
they don't solve cases where you need typescript inlined functionality locally in your code or to perform assertion with satisfies operator etc.
Comment by g947o 2 days ago
Comment by afavour 2 days ago
Comment by culi 2 days ago
TypeScript utility types are available in JSDoc. You can pretty much copy-paste any typescript Type/Interface into JSDoc
Comment by Mogzol 2 days ago
Comment by creatonez 2 days ago
This isn't really true anymore, they have systematically added pretty much every type system feature to the JSDoc-like syntax.
Comment by g947o 2 days ago
Comment by trekz 2 days ago
You keep repeating this throughout the thread. Can you give an example?
Comment by spartanatreyu 2 days ago
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"?
Comment by matt_kantor 1 day ago
/** @typedef {`${number}.${number}.${number}`} SemVer */
Here's a playground: https://www.typescriptlang.org/play/?filetype=js#code/PQKhAI...Comment by spartanatreyu 1 day ago
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.
Comment by matt_kantor 1 day ago
What do you mean by this? Can you share an example?
Regular expressions do not act as type guards, and there's no way to express a type that allows one regular expression but rejects another (they're all just `RegExp`): https://www.typescriptlang.org/play/?target=5#code/MYewdgzgL...
Comment by spartanatreyu 21 hours ago
`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).
Comment by matt_kantor 12 hours ago
> RegExpExecArray gives you a structure that looks different between the jsdoc version and the typescript version.
> The typescript version has `.groups` inside RegExpExecArray.
The JSDoc version has `.groups` too, and it appears to be typed identically to the TypeScript version given similar configuration.
Here's the TypeScript version: https://www.typescriptlang.org/play/?target=5&strictNullChec...
And here's the JSDoc version: https://www.typescriptlang.org/play/?target=5&strictNullChec...
Could you show me what you mean in the playground? You can change it to JSDoc mode by selecting "JavaScript" in the "Lang" dropdown in the "TS Config" tab.
Comment by g947o 2 days ago
Comment by g947o 2 days ago
Comment by measurablefunc 2 days ago
Comment by crummy 2 days ago
ok i didn't think about this, that's an underrated benefit
Comment by agumonkey 2 days ago
Comment by g947o 2 days ago
Prefer Go To Source Definition
Makes `Go to Definition` avoid type declaration files when possible by triggering `Go to Source Definition` instead.
Comment by IshKebab 2 days ago
Comment by filleduchaos 2 days ago
Comment by sthuck 2 days ago
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?)
Comment by homebrewer 2 days ago
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).
Comment by matt_kantor 1 day ago
IDEA implements its own analysis and doesn't use tsserver at all. Its semantics diverge in subtle ways, I believe in both directions (some code that tsserver considers valid IDEA will consider invalid and vice versa).
Comment by zackify 2 days ago
Comment by TheRealPomax 2 days ago
"is" is doing a lot of heavy lifting there: JSDoc and TypeScript are two different ways to explicit prescribe typing in a way that tooling can use to determine correctness. The TS syntax is _far_ more powerful, but JSDoc can do most of the common TS use cases, for folks who want to stay in JS land while still benefiting from type tooling (either invoked or straight up built into the IDE).
Comment by culi 2 days ago
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
Comment by anovick 1 day ago
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++".
Comment by matt_kantor 1 day ago
Comment by anovick 18 hours ago
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).
Comment by matt_kantor 11 hours ago
Unlike ISO C++ I'm not aware of any standard for what JSDoc is outside of specific implementations. There's a bunch of stuff documented on https://jsdoc.app/ but it only partially overlaps with the JSDoc syntax that TypeScript uses, and is not what the article is talking about.
The situation is not unlike Markdown before the CommonMark standard (except with less pressure to standardize, because most codebases are written with specific tooling in mind). Maybe we should refer to it as "TypeScript-flavored JSDoc".
Comment by KPGv2 1 day ago
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"
Comment by Sammi 2 days ago
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.
Comment by TheRealPomax 4 hours ago
JSDoc is its own spec, and is not typescript, and is absolutely not at type annotation parity with typescript. Plenty of things that are hard to type in TS that are impossible to annotate use JSDoc.
So: just because tsc, the tool, can read in typing information that was written in JSDoc, does not make JSDoc typescript. tsc simply supports JSDOc. Very handy! Not the same thing in the slightest.
1. "typescript"
2. "can be read by tsc"
3. "anything that tsc can read"
Comment by sntxcmp 2 days ago
Comment by llimllib 2 days ago
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
Comment by sureglymop 2 days ago
Comment by culi 2 days ago
Comment by pjmlp 2 days ago
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.
Comment by akst 2 days ago
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 for bundling but still not too worried about using JSDoc over TS.
This might be my config, but one thing that does annoy me is whenever I define a lambda, I need to add an doc type. I guess if that's disincentivising me from writing lambdas maybe I should just add a TS compile step lol.
----------------------
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...
Comment by g947o 2 days ago
Comment by akst 2 days ago
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.
Comment by tobyhinloopen 1 day ago
Comment by spoiler 1 day ago
Comment by eevilspock 1 day ago
Comment by braebo 15 hours ago
Comment by g947o 2 days ago
Basically, the fact that it works does not mean it works well, and I don't recommend anyone going in this other direction unless they understand what they are getting into.
Comment by culi 2 days ago
Curious what limitations there are on static type checking. It seems like a matter of your IDE setup
> My own experience is that the DX with "real" TypeScript is much, much better than JavaScript with JSDoc
I agree with the DX point. I would just point out that if you're using JSDoc and getting intellisense from it, you are using TypeScript
Comment by g947o 2 days ago
Comment by CSSer 2 days ago
More broadly, this is the default behavior of JS even without JSDoc blocks, and it ought to be the default behavior everywhere, including TS. I'm not alone in this sentiment, but it's incredibly contentious. There's been an open GH issue about it with hundreds of replies for years. I have no idea why they can't just pick a different shortcut for viewing types and call it a day. They'd be doing the entire ecosystem a favor.
Comment by w3news 1 day ago
Best thing for me was not removing the code transformation (convert ts to js), but separate runtime code with documentation code, like the types. Gives you much more clear insight that the types you write to describe what you expect the type will be is not forced on runtime, but is just for you as developer to know it. And when you validate the input is the right type, it is much more clear that it is the runtime type validation.
You can still use JSDoc in your typescript files, but why do you want to do that? There is no reason to do that.
So using JSDoc or Type Annotation, both works the same, same benefits, it is only personal preferences. Both have its pros and cons. For me the JSDoc has more benefits. Some other people prefer annotations. But there is not 1 that is better in controlling the types, has more options. (Also the enum can be done if you are using JSDoc, but is a little different)
Comment by supernes 1 day ago
JSDoc is more than type annotations. I use it for method and parameter descriptions, deprecation notices, inline examples, etc even in TS files.
Comment by auggierose 1 day ago
Just use TypeScript.
Comment by jcbhmr 2 days ago
npm displays packages with bundled TypeScript declarations https://github.blog/changelog/2020-12-16-npm-displays-packag...
JSDoc-typed node modules require special configuration in consumers to be useful https://github.com/microsoft/TypeScript/issues/19145
Comment by sureglymop 2 days ago
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.
Comment by umanwizard 2 days ago
Doesn't this describe every programming language?
When you write C, you are technically not writing machine code.
Even when you write JavaScript, what actually gets executed is V8 bytecode and/or machine code (depending on whether the JIT fires).
Comment by sureglymop 2 days ago
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.
Comment by vlovich123 2 days ago
Comment by sureglymop 2 days ago
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.
Comment by wvenable 2 days ago
Occasionally, I have to remember that JavaScript has no types at runtime but it's surprisingly not that often.
Comment by sureglymop 2 days ago
However I have been in a few situations at work where all of a sudden we did have issues that required us to dig deeper. There were also some bundling related issues that caused problems in production deployments. At that point many co workers had no idea how to even approach it to be honest.
Comment by wvenable 2 days ago
Comment by kaufmann 2 days ago
(asking to learn)
Comment by sureglymop 2 days ago
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.
Comment by Lorin 1 day ago
Comment by n2d4 1 day ago
Comment by Lorin 1 day ago
Comment by conartist6 2 days ago
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
Comment by sethaurus 2 days ago
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 runtime type-checking would completely dominate the code, and nobody does it. Many invariants which exist at compile-time cannot be meaningfully checked at runtime, even if you wanted to. All you can do is offer a type-safe interface, trust your callers to respect it, and check for a few common mistakes at the boundary. You cannot protect your code against other code calling it incorrectly, and in practice nobody does. This is equally true for JS and TS.
Comment by md224 2 days ago
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.
Comment by billyp-rva 2 days ago
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.
Comment by conartist6 2 days ago
Usually there's little if any protection against a JS caller providing wrong-type args to TS functions.
Comment by md224 2 days ago
I'm also not sure we're actually disagreeing on anything, so perhaps my reply was pointless. I agree that if you mix JS and TS in the way you describe, you'll have problems. My reply was just to say "yes, and that's not really Typescript's fault", but perhaps you weren't implying that to begin with.
* 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.
Comment by conartist6 1 day ago
Comment by umanwizard 2 days ago
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.
Comment by epolanski 2 days ago
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/
Comment by girvo 2 days ago
Comment by epolanski 2 days ago
Comment by culi 2 days ago
Comment by girvo 1 day ago
Comment by auxiliarymoose 2 days ago
A bonus of this approach is that it clearly delineates what type information is available at runtime, vs what type information is just a comment. (especially useful when working with serialized data).
I also like that it generally means all of the preconditions and postconditions for functions are in a single place (both the prose and the technical information are in the JSDoc comment), keeping the code itself low-noise and boiled down to its essence, and providing a natural place to write example inputs and outputs to guide usage.
As for generic types, I use them extensively, and this is made less verbose e.g. on function calls by using an @type annotation on the function which accepts a TypeScript signature without needing separate @template + @param annotations.
It's awesome stuff, and I'm happy that TypeScript works so well with JSDoc!
Comment by Brysonbw 2 days ago
Also, you can use both (if that's what you prefer).
Comment by hilarycheng 1 day ago
Comment by Hrun0 1 day ago
Comment by embedding-shape 1 day ago
Comment by culi 1 day ago
Comment by Merad 1 day ago
Comment by matt_kantor 1 day ago
Comment by columk 1 day ago
If it's your own library you can add declarationMap: true to your tsconfig.
I almost always want to see the source when I cmd+click.
Comment by notpushkin 2 days ago
Comment by mohsen1 2 days ago
Comment by culi 2 days ago
Comment by neallindsay 2 days ago
Comment by pyrolistical 2 days ago
Comment by christophilus 2 days ago
Comment by gaigalas 2 days ago
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.
Comment by conartist6 2 days ago
Comment by gaigalas 2 days ago
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.
Comment by conartist6 2 days ago
Comment by prmph 2 days ago
Comment by conartist6 2 days ago
Comment by indolering 2 days ago
Comment by conartist6 2 days ago
Comment by gaigalas 2 days ago
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).
Comment by conartist6 2 days ago
Comment by gaigalas 2 days ago
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.
Comment by conartist6 2 days ago
Comments are a kind of freedom in code. You're completely free to use them precisely because (in a plain execution environment) they cannot influence the result of evaluation
If comments /can/ change the result of evaluation then you simply are not (completely) free to use them. (And yes I know that this is a simplification in JS where you can already get the source code of a function with toString... Ugh)
Comment by gaigalas 2 days ago
Comment by botten 2 days ago
Comment by conartist6 2 days ago
Comment by herpdyderp 2 days ago
Comment by conartist6 2 days ago
I'm currently in the process of trying to pull together our first big release.
Comment by g947o 2 days ago
Comment by apatheticonion 1 day ago
/
index.js
index.d.ts
Where values in `index.js` can be typed in the header file with complete TypeScript syntax and those types are present in the target file via intellisense and type checking // index.js
function useStr(x){} // has intellisense for "string"
useStr("Hello")
useStr(42) // IDE and type checker error
And // index.d.ts
declare function useStr(x: string): voidComment by MrJohz 1 day ago
The advantage of JSDoc is that the TypeScript compiler treats it as equivalent to TypeScript source code, which means you've still got access to type checking inside your functions.
One thing I've seen in a few places is still to have DTS files that declare all sorts of types that are used in the application, and then have those files imported by JSDoc comments. That way, you've got TypeScript syntax for your types, which tend to get bulky and difficult to read in JSDoc syntax, but you still don't need a build system because the DTS imports are ignored completely at runtime.
Comment by apatheticonion 1 day ago
There are three issues with that.
The first is that JSDoc doesn't support everything you need in TypeScript and there is a lot of inlining (like typedef causes collisions, there's no importing a type without also re-exporting it from the importing file unless you inline the import)
The second is that JSDoc isn't picked up from imported libraries (or at least I don't think it is?)
Lastly, you still need a transpiler to remove the comments and build d.ts files.
In the end, JSDoc isn't practical for projects. The header file strategy means you don't need to transpile ever (only a typechecker) and you'd get the full suite of TypeScript functionality - at the cost of synchronization overhead.
For a project using JSDoc, you'll graduate to TypeScript when there is sufficient complexity anyway. Migrating from a d.ts file is way easier (potentially automatable) than migrating from JSDoc.
Comment by MrJohz 1 day ago
So even if TypeScript did check the header file against the implementation, you'd still need additional annotations inside the implementation file. At that point, why not put all the annotations inside the implementation file directly?
Regarding your points:
1. JSDoc does support everything that TypeScript supports (that's the point of this article), although it does not necessarily support it as cleanly, hence why projects like Svelte typically use DTS files to define the project's types, and have those be imported inside JSDoc annotations. It's not perfect, but it gets you a long way.
2. You're right, JSDoc isn't picked up from imported libraries, but if you're publishing a library, you'll have a build script there, and at that point it's typical to generate the DTS files and pack those with the source code. That seems fairly reasonable to me — while developing, you don't need to worry about building files, but then when packaging and releasing you do.
3. You don't need a transpiler with JSDoc, the point behind JSDoc is that it's literally just the pre-existing JS documentation syntax. You can (and should) leave the comments in. Even if you're using TypeScript syntax, you should have JSDoc annotations (although adding the types to those annotations is redundant in that case). You can also just include the DTS files. As long as they're only imported from JSDoc, the runtime won't see them.
Personally, having tried out JSDoc-based TypeScript, I'd rather just use the native type stripping in Node for development, and keep with TS syntax, but there are large projects that have made the opposite choice, most noticeably Svelte. So I don't think it's a given that JSDoc users will inevitably graduate to TypeScript (especially when projects have gone in the opposite direction).
Comment by eezing 2 days ago
Discriminated unions, conditional types, mapped types, template literal types, recursive type aliases, higher-kinded type patterns, generic constraints with conditional inference, the infer keyword, never type exhaustiveness checking, const assertions, readonly tuple and array inference, exact object types, key remapping in mapped types, indexed access types, variance annotations, assertion signatures, strict null checking with flow-sensitive narrowing, definite assignment assertions, the satisfies operator, declaration merging, module augmentation, symbol-typed properties, type-safe enums
…and not written via comments
Comment by culi 2 days ago
I really mean it. You can even use the @satisfies operator like so
/** @satisfies {Type} */
Discriminated unions, conditional types, mapped types, template literal types, etc work exactly the same way if you define them in a JSDoc comment as if you define them in a .ts fileComment by cutler 2 days ago
Comment by paulddraper 2 days ago
However, the precision and completeness is not nearly what can be expressed in TypeScript. With generics particularly.
Comment by culi 2 days ago
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
Comment by paulddraper 1 day ago
Which is a lot different than vanilla JSDoc [1].
I understand.
Comment by culi 1 day ago
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)
Comment by user3939382 2 days ago
Comment by culi 2 days ago
Comment by user3939382 1 day ago
Comment by brazukadev 2 days ago
Comment by jason_oster 2 days ago
Comment by casmn 2 days ago
Comment by strongpigeon 2 days ago
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, many flaws, and no resources to improve it.
But hey, at least it wasn’t GWT.
Comment by culi 2 days ago
Comment by pavo-etc 2 days ago
Comment by culi 2 days ago
Comment by efortis 2 days ago
---
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
---
And in jsdoc you can have an inline description:
@prop {number} width Video width in pixelsComment by culi 2 days ago
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.
Comment by epolanski 2 days ago
https://github.com/tc39/proposal-type-annotations?tab=readme...
Comment by culi 2 days ago
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
Comment by g947o 2 days ago
I found several limitations and already opened several issues on github.
Comment by efortis 2 days ago
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.
Comment by epolanski 2 days ago
If you need precise return typing, conditional types, literal values, etc, you aren't going far if anywhere with JSDoc.
Comment by efortis 2 days ago
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.
Comment by g947o 2 days ago
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.
Comment by afavour 2 days ago
But it’s more annoying than just writing TypeScript. There are ways to express just about everything TypeScript can but they’re all more difficult and convoluted (generics are a great example). For a project of any reasonable size I’m still going to advocate to use TypeScript.
Comment by sgammon 2 days ago
Comment by sgammon 2 days ago
Comment by zwb2324550 1 day ago
Comment by sgammon 2 days ago
Comment by austin-cheney 2 days ago
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.
Comment by christophilus 2 days ago
Comment by austin-cheney 2 days ago