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!]