Hacker News new | ask | show | jobs
by eyelidlessness 1046 days ago
Some of the limitations listed are wrong:

> The main limitation is that you don't have access to some TypeScript-specific syntax.

> * as, also known as type assertions (or casts)

You generally shouldn’t (as the article notes), but you can:

  const foo = /** @type {Bar} */ ({
    something: {
      satisfying: 'Bar',
    },
  });
Note: the parentheses are necessary, they are the JS/JSDoc mechanism for type casts.

This also works for `as const`, which is often better when you can use readonly types:

  const foo = /** @type {const} */ ({
    something: 'else',
  });
  // { readonly something: 'else' }
Better still, the satisfies operator also works (its JSDoc support lagged a bit though):

  /** @satisfies {Bar} */
  const foo = …;
This will infer the type of `foo` and check it for assignability to `Bar`.

> * is, also known as type predicates

This definitely works:

  /**
   * @param {unknown} value
   * @return {value is Foo}
   */
  const isFoo = (value) => …
You can also define the guard as a standalone/assignable type:

  /**
   * @callback IsFoo
   * @param {unknown} value
   * @return {value is Foo}
   */
The @callback tag is ~equivalent to a type alias for a function signature.

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:

  /**
   * @template T
   * @callback IsT
   * @param {unknown} value
   * @return {value is T}
   */

  /** @type {IsT<Foo>} */
  const isFoo = (value) => …
[Disclaimer: typed this comment on my phone from memory, apologies for any typos or mistakes!]