david_adler
david_adler

Reputation: 10902

Typescript jsdoc with annotate parameter property

I am trying to annotate a property of an object which is an argument to a function.

Specifically I want options.length explanation to appear in vscode when hovering over the function definition.


/**
 * Memoize a function
 * @param  {(...fnArgs: T[]) => U} fn The function to memoize
 * @param  {Object} options Memoization options
 * @param  {number} options.max The max size of the LRU cache
 * @param  {number | undefined} options.length The response will be cached
 *  by the first N args, based on this value. Trailing args will still be
 *  passed to the underlying function but will be ignored during memoization.
 */
export const memo = <T, U>(
  fn: (...fnArgs: T[]) => U,
  { max, length }: { max: number; length?: number }
) => {
  const cachedArgs: T[][] = []
  const cachedValues: U[] = []
  const get = (args: T[]): U | undefined => {
    const index = cachedArgs.findIndex(x => argsAreEqual(x, args, length))
    if (index === -1) return
    onUsed(index)
    return cachedValues[index]
  }

  const set = (args: T[], value: U) => {
    cachedArgs.push(args)
    cachedValues.push(value)
  }

  const onUsed = (index: number) => {
    moveToEnd(index, cachedArgs)
    moveToEnd(index, cachedValues)
  }

  const prune = () => {
    if (cachedArgs.length >= max) {
      cachedArgs.shift()
      cachedValues.shift()
    }
  }
  return (...args: T[]) => {
    let value = get(args)
    if (value) return value
    prune()
    value = fn(...args)
    set(args, value)
    return value
  }
}

When hovering over the type signature I get the following

@param fn — The function to memoize
@param options — Memoization options

enter image description here

I've done my best to copy from the docs but it doesn't show the explanation for options.length.

I want it to show the explanation for how the options.length parameter works. How can I do this?

Bonus question, not sure how to make the generics work with jsdoc either... help with @template much appreciated!

Upvotes: 3

Views: 1287

Answers (1)

jcalz
jcalz

Reputation: 327744

This behavior seems to be a known bug, whereby destructured parameters do not have their JSDoc comments displayed: microsoft/TypeScript#24746. I'm not really sure why, but according to a comment, giving a @param a type of Object is equivalent to giving it a type of any, and you can get the behavior you want by using a different type. In the following I change Object to {}:

/**
 * @param  {(...fnArgs: T[]) => U} fn
 * @param  {{}} options Memoization options
 * @param  {number} options.max The max size of the LRU cache
 * @param  {number | undefined} options.length The response will be cached
 *  by the first N args, based on this value. Trailing args will still be
 *  passed to the underlying function but will be ignored during memoization.
 */
export const memo = <T, U>(
  fn: (...fnArgs: T[]) => U,
  { max, length }: { max: number; length?: number }
) => { }

and your IntelliSense starts to work, at least when hovering over the function. (I don't think it's possible to get comments when you hover over the actual identifier named max or length in your code). Observe:

/* IntelliSense shows:
const memo: <T, U>(fn: (...fnArgs: T[]) => U, { max, length }: {
    max: number;
    length?: number | undefined;
}) => void   
@param fn  
@param options — Memoization options    
@param options.max — The max size of the LRU cache    
@param options.length — The response will be cached by the first N args,
  based on this value. Trailing args will still be passed to the
  underlying function but will be ignored during memoization.    
*/

PLEASE NOTE that this only seems to work for TypeScript code (like .ts or .tsx) and not JavaScript code. If you do this in JavaScript, the compiler will complain about anything other than Object or object.


As for your bonus question, I think it should work in TypeScript just like it does in JavaScript:

/** 
 * @template T the arg type of fn
 * @template U the return type of fn
 * @param  {(...fnArgs: T[]) => U} fn

which shows me

/* IntelliSense shows:
const memo: <T, U>(fn: (...fnArgs: T[]) => U, { max, length }: {
    max: number;
    length?: number | undefined;
}) => void
@template — T the arg type of fn
@template — U the return type of fn 
@param fn
*/

Playground link to code

Upvotes: 3

Related Questions