Skip to content

JSDoc: settle how we document destructured component props #34

Open

Description

@troychaplin

In #18, @joedolson flagged src/settings/index.tsx:94:

I'm not a big fan of using unnamed parameters, but I think that's not a blocker for accepting this PR, since the purpose of the PR is to address linting issues without changing the code.

Agreed it wasn't in scope there. Filing it so we can settle the pattern, since it'll recur in every TSX component we document.

What it refers to

/**
 * A single badge. Only rendered when the module is genuinely in that
 * state — "Stable" is the default and never gets a chip.
 * @param root0
 * @param root0.kind
 * @param root0.label
 */
function Badge( { kind, label }: { … } ): JSX.Element {

root0 is eslint-plugin-jsdoc's placeholder for a destructured parameter with no name — generated by the jsdoc/require-param autofix.

The awkward part

In @wordpress/eslint-plugin's config:

  • jsdoc/require-jsdoc → off (docblocks optional)
  • jsdoc/require-param → error (but if you write one, every param must be tagged)
  • jsdoc/require-param-description → off (tags need no description)

So writing a helpful prose docblock forces bare @param root0.kind tags that convey nothing, while leaving the component undocumented stays clean. ModuleBadges (index.tsx:114) and IssueRow (sidebar.tsx:18) destructure props exactly the same way and have no tags — only because neither has a docblock. The rule effectively penalizes documenting.

Worth knowing: upstream Gutenberg has ~74 @param root0 tags, so the name itself is tolerated there — but theirs carry real descriptions (@param root0.src Image source URL.). Ours have none, so we get the ugly name and no information.

Scope

9 tags, 2 functions, 1 file: Badge (src/settings/index.tsx:98) and ModuleRow (:152). Small today — the question is what we do going forward.

Options

A — Name the parameter. Take props and destructure in the body:

function Badge( props: BadgeProps ): JSX.Element {
	const { kind, label } = props;

Gives a single @param props tag and directly answers the objection. Costs one line per component.

B — Keep root0, require descriptions. Match Gutenberg: turn on jsdoc/require-param-description so the tags at least earn their place. Doesn't fix the naming.

C — Disable the jsdoc param rules for .ts/.tsx. The TypeScript annotations already give every param a name and type; @param root0.kind is strictly redundant with kind: 'experiment' | 'core-track'. Lets docblocks carry prose only, which is the part that actually helps.

Suggestion

C, possibly with A where a named props type reads better anyway. In a TypeScript codebase the param tags duplicate the type signature, and removing the requirement means documenting a component no longer costs you a block of noise.

Whichever we pick belongs in CONTRIBUTING.md alongside the PHP docblock standards, which are already documented in detail.

Activity

  1. aduth commented on Sep 29, 2026

    @aduth
    Member

    C — Disable the jsdoc param rules for .ts/.tsx. The TypeScript annotations already give every param a name and type; @param root0.kind is strictly redundant with kind: 'experiment' | 'core-track'. Lets docblocks carry prose only, which is the part that actually helps.

    There's precedent for this in Gutenberg, for what it's worth. It's rather coarse though, assuming that .tsx files primarily contain a single component function whose params are self-evident by nature of it being a React component.

    The documentation should be expected to come through from the associated TypeScript types, which themselves should have JSDoc annotations on each of their interface prop members.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions