Table of Contents#
- JSDoc Basics: A Quick Recap
- Documenting Array Parameters
- Documenting Array Return Values
- Handling Nested Arrays
- Best Practices for Array Documentation
- Common Pitfalls to Avoid
- 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 ofnumberelements. - 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 containsUserinstances, 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
@propertyto 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
@typedefto 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 ofnumber[]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#
- JSDoc Official Documentation
- TypeScript JSDoc Support
- MDN Web Docs: JSDoc
- VS Code JSDoc IntelliSense
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! 🚀