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)
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)
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(); /**
* @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;
};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.
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.
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.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.
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
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.
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.
TypeScript utility types are available in JSDoc. You can pretty much copy-paste any typescript Type/Interface into JSDoc
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"?
/** @typedef {`${number}.${number}.${number}`} SemVer */
Here's a playground: https://www.typescriptlang.org/play/?filetype=js#code/PQKhAI...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.
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...
`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).
> 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.
It isn't narrowed down to the actual named capture groups inside the regex.
For the whole semver example, we'd want something typed as: { major: string, minor: string, patch: string }.
(sidenote for this semver example and not regex in general: they will be strings because a major of "01" and a patch of "3-prerelease" are both valid. You can parse them into ints later depending on what you're actually doing with the semver)
---
For an example of a type narrowed regex in the ts playground, I'll take the lazy route and point you to an example someone else has made:
https://www.typescriptlang.org/play/?ssl=1&ssc=39&pln=1&pc=3...
You can use a utility library (e.g. ts-regexp, arkregex, etc...), you can use one of the utilities that are shared around the typescript spaces online for the one part you need, or you can make your own utility type.
---
For my use-case, I just want to know that I can change either my code or regex and I'll be alerted before runtime or buildtime if I've forgotten to account for something.
To carry on with the semver example, if a fourth piece of data was added to the incoming string (e.g. product name, build timestamp, build variant, etc...) and I forgot to update both the code and the regex together and instead only updated one, I'd want an alert in my IDE to tell me that I forgot to update the other one.
The behavior of ts-regexp is not especially related to the `RegExpExecArray` type. That package uses unsafe assertions to implement its API.
The only thing that requires TypeScript syntax in the playground you linked is the non-null assertions. Here's that same code in JSDoc mode with the non-null assertions removed (`strictNullChecks` is disabled instead): https://www.typescriptlang.org/play/?filetype=js#code/JYWwDg...
---
> For my use-case, I just want to know that I can change either my code or regex and I'll be alerted before runtime or buildtime if I've forgotten to account for something.
If you can show a concrete example what you want using TypeScript syntax then I'm pretty sure I could port it to JSDoc syntax. (To be clear I'd personally much rather write the TypeScript syntax as I find JSDoc comments annoying & verbose, but they're plenty powerful, being nearly isomorphic to TypeScript annotations.)