How to write a JSDoc for an object with different types of keys?
Asked Answered
C

1

13

The JSDoc api says you can document objects like so:

{Object.<string, number>}

and document multiple type:

{(number|boolean)}

But if I try to specify an object that could have strings OR numbers as the key, it does not work. VSCode/JSDoc just reports the type as 'any'.

VSCode does not understand:

/**
 * Object with string or number for keys
 * @param {Object.<(string|number), any>} Container
 */

I've also tried this in @typedef, or defining the key in it's own @typedef to no effect.

Because I'm using & to get an intersection of types (like {Object.<string, any> & {'foo': number}} I don't want to have to use the boolean or to say:

/**
 * Object with string or number for keys
 * @param {(Object.<string, any>|Object.<number, any>) & {'foo': number}} Container
 */

The type documented ends up looking something like:

 type Container = ({
    [x: string]: any;
  } & {
    'foo': number;
  }) | ({
    [x: number]: any;
  } & {
    'foo': number;
  })

Which is needlessly verbose.

Is there way to document this with a more succinct output?

Contrary answered 29/11, 2021 at 18:41 Comment(0)
A
12

In JavaScript, object keys are always strings (or, in the case of numbers, coerced into strings), so you might be needlessly complicating things. See the ECMAScript spec on Objects:

Properties are identified using key values. A property key value is either an ECMAScript String value or a Symbol value. All String and Symbol values, including the empty String, are valid as property keys. A property name is a property key that is a String value.

An integer index is a String-valued property key that is a canonical numeric String

That said, this seems like the most straightforward solution:

// Combined
/**
 * @param {Object.<string, any> & {foo:  number}} Container
 */

// Split/reusable
/**
 * @typedef {Object.<string, any>} GenericObject
 * @param {GenericObject & {foo: number}} Container
 */

Both of the above result in this type/documentation:

Container: {
    [x: string]: any;
} & {
    foo: number;
}

Declaring Object.<string, any> seems a bit redundant to me since object keys are inherently strings and values are inherently any, so declaring it this way doesn't provide much value to a developer.

Aery answered 3/12, 2021 at 18:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.