The problem with @param is that it requires a binding name
I ended up doing this instead:
/**
@typedef {{x: string}} FooArgs
@typedef {{y: string}} FooResult
@type {function(FooArgs): FooResult}
*/
export const foo = ({x}) => ({y: x});
It works, but the double curly feels a bit clunky. Compare to Flow:
/*::
type FooArgs = {x: string};
type FooResult = {y: string};
type Foo = (FooArgs) => FooResult;
*/
export const foo /*: Foo */ = ({x}) => ({y: x});
In Flow, the declaration ends up looking essentially the same between comment syntax and non-comment syntax.
With TS, RORO ends up looking like Flow (but with weirder indentation on large enough structs), whereas I'd prefer to express regular functions in terms of @callback, @param and @returns since that's more in line w/ the spirit of jsdoc. Not a huge deal, in any case, considering the upsides of comment syntax.