javascriptroom blog

How to Document Array Return Values and Parameters in JSDoc: Handling Type or Object Literal Elements

In dynamic languages like JavaScript and TypeScript, clear documentation is critical for maintaining readability, reducing bugs, and enabling collaboration. JSDoc, a markup language for annotating JavaScript code, helps address this by providing a standard way to describe code behavior, types, and usage. Among the most common (and often tricky) elements to document are arrays—especially when they contain specific types (e.g., string[], User[]) or complex object literals (e.g., arrays of { id: number, name: string }).

Whether you’re documenting function parameters that accept arrays or return values that resolve to arrays, precision is key. Vague array documentation (e.g., {Array}) leaves developers guessing about element types, leading to errors. This guide will demystify JSDoc syntax for arrays, covering primitive types, custom types, object literals, nested arrays, and best practices to ensure your docs are clear and actionable.

2026-01

Table of Contents#

  1. JSDoc Basics: A Quick Recap
  2. Documenting Array Parameters
  3. Documenting Array Return Values
  4. Handling Nested Arrays
  5. Best Practices for Array Documentation
  6. Common Pitfalls to Avoid
  7. Reference

1. JSDoc Basics: A Quick Recap#

Before diving into arrays, let’s recap core JSDoc concepts:

  • Tags: Special keywords (e.g., @param, @returns) that describe code elements.
  • Type Annotations: Enclosed in {} to specify data types (e.g., {string}, {number}).
  • Descriptions: Plain text explaining the purpose of a parameter, return value, etc.

For example, a simple function with a string parameter and number return value might be documented as:

/**
 * Returns the length of a string.
 * @param {string} str - The input string to measure.
 * @returns {number} Length of the input string.
 */
function getStringLength(str) {
  return str.length;
}

JSDoc supports TypeScript-like type syntax for complex structures, including arrays. This is where we’ll focus next.

2. Documenting Array Parameters#

Arrays are used to pass collections of values to functions. To document them, you need to specify:

  • The fact that it’s an array.
  • The type of elements in the array (primitives, custom types, or object literals).

2.1 Arrays with Primitive/Built-in Types#

For arrays containing primitives (e.g., string, number, boolean) or built-in objects (e.g., Date), use the syntax {Type[]}. This tells readers the parameter is an array where every element is of Type.

Example: Summing an Array of Numbers#

/**
 * Calculates the sum of all numbers in an array.
 * @param {number[]} numbers - Array of numeric values to sum.
 * @returns {number} Total sum of the array elements.
 */
function sumArray(numbers) {
  return numbers.reduce((acc, curr) => acc + curr, 0);
}
  • Syntax Breakdown: {number[]} indicates an array of number elements.
  • Why It Works: IDEs like VS Code will use this to enforce type checks (e.g., flagging non-numeric values) and provide autocompletion.

2.2 Arrays with Custom Types#

If your array contains instances of a custom class, interface, or type (e.g., User, Product), replace Type with the custom type name.

Example: Processing an Array of User Objects#

Suppose you have a User class:

class User {
  constructor(name, age) {
    this.name = name; // string
    this.age = age;   // number
  }
}

Document a function that processes an array of User instances:

/**
 * Filters users to return only adults (age ≥ 18).
 * @param {User[]} users - Array of User objects to filter.
 * @returns {User[]} Array of adult User objects.
 */
function getAdults(users) {
  return users.filter(user => user.age >= 18);
}
  • Key Point: {User[]} clearly signals the array contains User instances, not generic objects.

2.3 Arrays with Object Literals#

When arrays contain anonymous object literals (e.g., { id: 1, name: "Apple" }), you need to document the structure of the objects within the array. Use one of two syntaxes:

Syntax 1: Array.<{property: Type, ...}> (Legacy)#

Older JSDoc versions use Array.<...> to denote generic arrays. For object literals:

/**
 * Formats product names for display.
 * @param {Array.<{id: number, name: string}>} products - Array of product objects.
 *   @property {number} products[].id - Unique product identifier.
 *   @property {string} products[].name - Product display name.
 * @returns {string[]} Formatted product names (e.g., "1: Apple").
 */
function formatProductNames(products) {
  return products.map(product => `${product.id}: ${product.name}`);
}

Syntax 2: { {property: Type, ...}[] } (Modern, Preferred)#

Modern JSDoc (and TypeScript) support the more readable { {prop: Type}[] } syntax, where the inner {} defines the object literal:

/**
 * Formats product names for display.
 * @param {{id: number, name: string}[]} products - Array of product objects.
 *   @property {number} products[].id - Unique product identifier.
 *   @property {string} products[].name - Product display name.
 */
function formatProductNames(products) {
  return products.map(product => `${product.id}: ${product.name}`);
}
  • Why Syntax 2 is Better: It’s more concise and aligns with TypeScript’s array syntax, making it familiar to most developers.
  • Documenting Object Properties: Use @property to describe each field in the object literal (e.g., products[].id).

3. Documenting Array Return Values#

Documenting array return values follows similar logic to parameters, but uses the @returns tag instead of @param.

3.1 Returning Arrays of Primitives/Custom Types#

For arrays of primitives or custom types, use {Type[]} with @returns.

Example: Returning an Array of Strings#

/**
 * Generates an array of greetings for a list of names.
 * @param {string[]} names - Array of names to greet.
 * @returns {string[]} Array of greeting strings (e.g., "Hello, Alice").
 */
function getGreetings(names) {
  return names.map(name => `Hello, ${name}`);
}

Example: Returning an Array of Custom Types#

/**
 * Creates an array of User objects from raw data.
 * @param {Array.<{name: string, age: number}>} rawData - Array of user data objects.
 * @returns {User[]} Array of User instances created from rawData.
 */
function createUsers(rawData) {
  return rawData.map(data => new User(data.name, data.age));
}

3.2 Returning Arrays of Object Literals#

When returning arrays of object literals, use the same { {prop: Type}[] } syntax as with parameters, and document nested properties.

Example: Returning Product Object Literals#

/**
 * Fetches product data from an API (mocked).
 * @returns {{id: number, name: string, inStock: boolean}[]} Array of product objects.
 *   @property {number} id - Unique product ID.
 *   @property {string} name - Product name.
 *   @property {boolean} inStock - Whether the product is in stock.
 */
function fetchProducts() {
  return [
    { id: 1, name: "Laptop", inStock: true },
    { id: 2, name: "Mouse", inStock: false }
  ];
}
  • Pro Tip: If the object literal structure is reused across parameters/return values, define a @typedef to avoid repetition (see Best Practices).

4. Handling Nested Arrays#

Nested arrays (e.g., arrays of arrays, or arrays of objects with array properties) require careful documentation to avoid ambiguity.

Example 1: Array of Arrays (2D Matrix)#

/**
 * Calculates the sum of all elements in a 2D matrix.
 * @param {number[][]} matrix - 2D array of numbers (e.g., [[1, 2], [3, 4]]).
 * @returns {number} Total sum of all matrix elements.
 */
function sumMatrix(matrix) {
  return matrix.flat().reduce((acc, curr) => acc + curr, 0);
}
  • Syntax: number[][] denotes an array of number[] arrays.

Example 2: Arrays with Nested Object Literals#

/**
 * Groups users by their favorite colors.
 * @param {{name: string, favoriteColors: string[]}[]} users - Array of user objects.
 *   @property {string} users[].name - User's name.
 *   @property {string[]} users[].favoriteColors - Array of color strings (e.g., ["red", "blue"]).
 * @returns {{color: string, users: string[]}[]} Array of color groups with user names.
 */
function groupByColor(users) {
  // Implementation logic...
}
  • Key Detail: favoriteColors: string[] clarifies that each user has an array of strings for colors.

5. Best Practices for Array Documentation#

1. Be Specific About Element Types#

Avoid vague annotations like {Array} or {Object[]}. Always specify element types (e.g., {string[]}, {User[]}) to guide developers and tools.

2. Prefer Type[] Over Array<Type> for Simplicity#

Both Type[] and Array<Type> are valid, but Type[] is more concise for simple arrays. Use Array<Type> only for complex generics (e.g., Array<{id: number}>).

3. Reuse Types with @typedef for Complex Object Literals#

If you repeatedly document the same object literal structure, define a @typedef to standardize and reduce redundancy:

/**
 * @typedef {Object} Product
 * @property {number} id - Unique product ID.
 * @property {string} name - Product name.
 * @property {boolean} inStock - Stock status.
 */
 
/**
 * Filters products by stock status.
 * @param {Product[]} products - Array of Product objects (see @typedef Product).
 * @param {boolean} inStock - Target stock status to filter.
 * @returns {Product[]} Filtered array of Product objects.
 */
function filterByStock(products, inStock) {
  return products.filter(product => product.inStock === inStock);
}

4. Document Nested Properties Explicitly#

For arrays of objects, use @property to describe nested fields (e.g., products[].id). This helps IDEs provide autocompletion for nested properties.

5. Test with IDEs#

VS Code, WebStorm, and other modern IDEs use JSDoc to validate types. Write a small test snippet to ensure your annotations trigger type hints and error warnings for invalid inputs.

6. Common Pitfalls to Avoid#

1. Omitting Element Types#

❌ Bad: @param {Array} numbers (What’s in the array? Strings? Objects?)
✅ Good: @param {number[]} numbers

2. Inconsistent Syntax#

Mixing Type[] and Array<Type> without reason harms readability:
❌ Bad: @param {Array<string>} names and @returns {number[]} sums
✅ Good: Stick to string[] and number[] for consistency.

3. Undocumented Nested Arrays#

❌ Bad: {Object[]} for an array of { tags: string[] } objects
✅ Good: {{tags: string[]}[]} with @property for tags.

4. Forgetting @property for Object Literals#

Without @property, developers won’t know the structure of object literals:
❌ Bad: @param {{id: number, name: string}[]} products (no property descriptions)
✅ Good: Add @property tags to explain id and name.

7. Reference#

By following these guidelines, you’ll ensure your array documentation is clear, actionable, and tool-friendly—making your codebase easier to maintain and collaborate on. Happy documenting! 🚀