Sorry for being <i>that</i> guy, but this should probably be called "typechecking without transpilation".<p>What ends up being written is not TypeScript syntax (which does require transpilation to run).<p>JSDoc is awesome for incremental adoption though, I've migrated a few codebases this way without too much pain.
JSDoc can get you pretty far, but it can be clumsy sometimes. There’s a [TC39 proposal](<a href="https://github.com/tc39/proposal-type-annotations">https://github.com/tc39/proposal-type-annotations</a>) to allow types to live in JS code and be treated as comments (similar with Python types today)
JSDoc comments are definitely <i>not</i> the “best of both worlds,” they are a limited and verbose subset of typing. I would only use them for specific reasons, like I’m in a hostile ecosystem that dogmatically doesn’t want any build steps (like WebGL/WebGPU engines).
I've found a happy medium to be annotating functions etc with JSDoc style comments but keeping interfaces etc. in a .d.ts file. The Typescript compiler is able to import it from a .js file just fine.
Some of the limitations listed are wrong:<p>> The main limitation is that you don't have access to some TypeScript-specific syntax.<p>> * as, also known as type assertions (or casts)<p>You generally shouldn’t (as the article notes), but you can:<p><pre><code> const foo = /** @type {Bar} */ ({
something: {
satisfying: 'Bar',
},
});
</code></pre>
Note: the parentheses are necessary, they <i>are</i> the JS/JSDoc mechanism for type casts.<p>This also works for `as const`, which is often better when you can use readonly types:<p><pre><code> const foo = /** @type {const} */ ({
something: 'else',
});
// { readonly something: 'else' }
</code></pre>
Better still, the satisfies operator also works (its JSDoc support lagged a bit though):<p><pre><code> /** @satisfies {Bar} */
const foo = …;
</code></pre>
This will infer the type of `foo` <i>and</i> check it for assignability to `Bar`.<p>> * is, also known as type predicates<p>This definitely works:<p><pre><code> /**
* @param {unknown} value
* @return {value is Foo}
*/
const isFoo = (value) => …
</code></pre>
You can also define the guard as a standalone/assignable type:<p><pre><code> /**
* @callback IsFoo
* @param {unknown} value
* @return {value is Foo}
*/
</code></pre>
The @callback tag is ~equivalent to a type alias for a function signature.<p>Also useful, if needed, the @template tag which is roughly equivalent to TS type parameters (generics) which you can use, for example, to assign generic type guards:<p><pre><code> /**
* @template T
* @callback IsT
* @param {unknown} value
* @return {value is T}
*/
/** @type {IsT<Foo>} */
const isFoo = (value) => …
</code></pre>
[Disclaimer: typed this comment on my phone from memory, apologies for any typos or mistakes!]
I'm using this setup at the moment, mostly because I work on legacy code base that has no good types yet.<p>Typically you would do jsconfig.json though, which is same as tsconfig.json but allowJs is already set. Mostly stylistic change, but some tooling might benefit for having jsconfig instead of tsconfig.
// @ts-check works until you need to do an assertion, a cast, a predicate, pass an explicit type to a generic method, etc., then it gets very annoying. I only ever use it if I’m writing a single self-contained and relatively short script and can’t be bothered with a build step.
Does anyone know if I have a TypeScript project, is there an automated process to turn it into this format this article describes? Eject for TS, I guess.
This is exactly how I use typescript, as a linter and static type analyzer for javascript. Unfortunately, typescript support for JSdoc is quite basic. So that method has its limit. But I'm not committing any typescript code.<p>Someone here just suggested to import type definition files with JS doc annotations, and that's actually a good idea.
Right on time as I've been trying to add some type safety onto my OSS project. Does anyone have some extra info on how to best leverage JSDoc to write safe(r) JS code?
I thought this was going to be a project like ts-node [1]<p>[1] <a href="https://github.com/TypeStrong/ts-node">https://github.com/TypeStrong/ts-node</a>