Publish and protect package APIs

Write TypeScript JSDoc Comments That Help API Consumers

Document TypeScript functions, interfaces, and React props with comments that explain intent without repeating types.

Editorial illustration for Write TypeScript JSDoc Comments That Help API Consumers

A useful API comment answers a question the signature cannot. If an exported function accepts two strings and returns a string, a caller can see those types already. They may still need to know which identifier to pass, where the result belongs, and whether it is suitable for anything besides display.

Put that answer in a /** ... */ block directly above the declaration. JSDoc-style comments in that position can appear in editor help (editor guidance). Start with a short summary; add detail where it helps someone make a choice.

Explain the arguments without retyping them

This function produces a label for an invoice list. The signature states the types; the comment explains the roles of its arguments and the intended use of its result.

/**
 * Builds a short label for an invoice list.
 *
 * @param number - The customer-facing invoice number, not its database key.
 * @param customerName - The name to display before the invoice number.
 * @returns A display label, not a stable identifier for looking up an invoice.
 */
export function invoiceLabel(number: string, customerName: string): string {
  return `${customerName.trim()} · Invoice ${number.trim()}`;
}

A caller might write invoiceLabel("INV-204", "Northwind"). The @param descriptions clarify that order and distinguish an invoice number from a database key. The @returns line warns against treating formatted display text as a lookup identifier. None of that follows from : string.

Avoid adding {string} to these @param lines. JSDoc type-information tags have a different role in JavaScript files; in TypeScript files, TypeScript supports documentation tags rather than those JSDoc type-information tags (TypeScript’s JSDoc reference). Repeating language-level annotations in comments also gives maintainers two places to update when a type changes (comment-ts guidance). Review the prose when the API’s meaning changes, too.

Put prop guidance where a React caller looks

An interface comment can describe a group of props. Property comments can then answer questions the individual types leave open. Here, the optional prop’s default is visible in the implementation, while its comment puts that choice beside the declaration a caller reads.

/** Props for a compact status label in a list row. */
export interface StatusBadgeProps {
  /** Text shown to users; avoid internal status codes here. */
  label: string;

  /** Tone class to apply. Omit to use the "neutral" tone. */
  tone?: "neutral" | "urgent";
}

/** Displays a status label in a list row. */
export function StatusBadge({
  label,
  tone = "neutral",
}: StatusBadgeProps) {
  return <span className={`status-badge--${tone}`}>{label}</span>;
}

<StatusBadge label="Paid" />;

The usage supplies the required label and omits tone, so the component uses its "neutral" default. label: string does not distinguish user-facing wording from an internal code. Nor does tone?: "neutral" | "urgent" by itself tell a reader what omission selects. The comments provide that guidance; they do not validate the label at runtime or supply styling for the CSS class. Keep the wording aligned with the implementation when either changes.

Comments on the interface, its properties, and the component serve different reading moments. A caller considering <StatusBadge label="Paid" /> needs the component’s purpose. Someone deciding whether to set tone needs the property guidance. Inspect both locations in your editor rather than assuming the interface comment alone answers every question.

Use extra tags for decisions, not decoration

An older exported name is a useful place to explain why it remains and where new callers should go:

/**
 * Builds an invoice-list label through the older entry point.
 *
 * @remarks
 * Kept for callers that have not yet changed their imports.
 *
 * @deprecated Use invoiceLabel for new callers.
 * @see invoiceLabel
 */
export function legacyInvoiceLabel(
  number: string,
  customerName: string,
): string {
  return invoiceLabel(number, customerName);
}

@deprecated gives a migration direction; @remarks explains the alias’s continued presence; @see points to the related function. TypeScript lists @deprecated, @see, and @link among supported documentation tags (TypeScript’s JSDoc reference). Do not assume an arbitrary JSDoc tag changes TypeScript behavior: unsupported tags are ignored. TSDoc proposes conventions because tools that read JSDoc-like syntax can interpret extensions differently (TSDoc). Choose tags your project’s tools present usefully, rather than decorating every declaration.

Read what consumers will read

After editing, open editor help for invoiceLabel, StatusBadge, and the relevant props. Check whether the opening summary appears where you expect it and whether parameter or property guidance is available at the point of use. If it is missing, first inspect which declaration the comment immediately precedes; then inspect how that editor presents comments.

Next, inspect the project’s generated reference output. Look for the same comments under the intended declarations, and check whether the deprecated alias directs readers toward invoiceLabel. This is a content review, not a reason to assume every editor and generator renders every tag alike. Delete prose that merely repeats a type; keep the details that help the next caller choose an argument, interpret a result, or move to a replacement API.

Find a note

Search by topic, title, or keyword.