Back to list
jasonkuhrt

writing-jsdoc

by jasonkuhrt

Tool configurations

1🍴 0📅 Jan 22, 2026

SKILL.md


Writing JSDoc

TypeScript-optimized JSDoc documentation guidance. TypeScript provides types; JSDoc provides meaning.

CRITICAL: No Type Repetition

TypeScript already has complete type information. Never duplicate it in JSDoc.

// ❌ BAD - Redundant type information
/**
 * @param {string} name - The user's name
 * @param {number} age - The user's age
 * @returns {boolean} Whether the user is valid
 */
function isValidUser(name: string, age: number): boolean { ... }

// ✅ GOOD - Description only, types come from TS
/**
 * Validates user meets minimum requirements.
 * @param name - Display name (must be non-empty)
 * @param age - Must be 13 or older
 */
function isValidUser(name: string, age: number): boolean { ... }

Forbidden in TS projects:

TagWhy Forbidden
@typeTS has the type
@param {Type}TS has param types
@returns {Type}TS has return type
@typedefUse TS type or interface
@callbackUse TS function types

What to Document

Document what TypeScript cannot express:

DocumentExample
Purpose/intent"Validates user meets minimum requirements"
Constraints"Must be non-empty", "Range: 0-100"
Side effects"Writes to localStorage", "Mutates input"
Exceptions@throws - TS doesn't track thrown errors
Defaults@default - Runtime default values
Examples@example - Usage patterns
Deprecation@deprecated - Migration guidance
External refs@see - Links to docs, specs

What NOT to Document

Skip JSDoc entirely for:

  • Self-evident code - getName() returning a name needs no docs
  • Internal helpers - Private functions used in one place
  • Type-only exports - Types are self-documenting
  • Trivial getters/setters - get id() { return this._id; }

JSDoc Placement Rules

DON'T Add JSDoc To

  • Namespace exports (export * as Name)
  • Barrel exports (export * from './foo')
  • Re-exports
  • Implementations that inherit documentation from their interface/type
  • Multiple JSDoc blocks for the same declaration (only closest one is effective)

Avoid Duplicate JSDoc

If a const implements an interface with JSDoc, don't repeat it on the const:

/** Creates a user validator. */
interface UserValidator {
  validate(user: User): boolean;
}

// ❌ BAD - Duplicates interface JSDoc
/** Creates a user validator. */
const validator: UserValidator = { ... };

// ✅ GOOD - Interface JSDoc is inherited
const validator: UserValidator = { ... };

Namespace Export Hack

For export * as Name, use @ts-expect-error with duplicate namespace to add docs:

// @ts-expect-error Duplicate identifier
export * as Utils from './utils'
/** Utility functions for string manipulation. */
export namespace Utils {}

Useful Tags for TypeScript

@throws

TypeScript doesn't track exceptions. Document them:

/**
 * Parses JSON configuration file.
 * @throws {SyntaxError} If JSON is malformed
 * @throws {Error} If file doesn't exist
 */
function parseConfig(path: string): Config { ... }

@example

Show usage patterns, especially for complex APIs:

/**
 * Creates a debounced version of a function.
 * @example
 * const debouncedSave = debounce(save, 300);
 * input.addEventListener('change', debouncedSave);
 */
function debounce<T extends (...args: any[]) => any>(fn: T, ms: number): T { ... }

@default

Document runtime defaults (complements TS default params):

interface Options {
  /** @default 3000 */
  timeout?: number
  /** @default 'warn' */
  logLevel?: 'debug' | 'info' | 'warn' | 'error'
}

@deprecated

Always include migration path:

/**
 * @deprecated Use {@link createUser} instead. Will be removed in v3.0.
 */
function addUser(name: string): User { ... }

@typeParam - Use Sparingly

Only document type parameters users explicitly provide:

// ✅ Document - user explicitly provides type
/**
 * Creates a type-safe event emitter.
 * @typeParam Events - Map of event names to payload types
 * @example
 * const emitter = createEmitter<{ click: MouseEvent; key: KeyboardEvent }>();
 */
function createEmitter<
  Events extends Record<string, unknown>,
>(): Emitter<Events>

// ❌ Don't document - type is inferred from arguments
/**
 * Returns first element of array.
 */
function first<T>(arr: T[]): T | undefined

The {@link} Tag

Create clickable references to types, functions, and identifiers.

Syntax

/** Composes {@link RhythmMediaPlayPauseButton} and {@link RhythmMediaTimeDisplay}. */

/** Returns result from {@link audiosByPriority | the priority list}. */

Import Requirement

For {@link Identifier} to be clickable, the identifier must be in scope:

ScenarioClickable?
Same file exportYes
Imported typeYes
Not importedNo (plain text)

JSDoc-Only Imports

When a type is needed only for {@link}, use underscore prefix to avoid lint errors:

// For JSDoc {@link} only
import type { MuxAsset as _MuxAsset } from '@heartbeat/types';

/**
 * Uploads audio to {@link _MuxAsset | Mux} for transcoding.
 */
export const uploadVoiceNote = async (blob: Blob) => { ... };

@see for Reference Docs

/**
 * Type-safe predicates for DOMException error types.
 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMException
 */
/**
 * Uploads audio to [Mux](https://www.mux.com/) for transcoding.
 */

Quick Reference

Use CaseSyntax
Link to identifier{@link Identifier}
Link with text{@link Identifier | display text}
External docs@see https://...
Inline link[Text](https://...)
Exception@throws {ErrorType} Description
Example@example + code block
Default value@default value
Deprecation@deprecated Use X instead
JSDoc-only importimport type { X as _X }

Notes

  • TypeScript provides types; JSDoc provides meaning and context
  • {@link} requires identifier in scope (imported or same file)
  • Underscore-prefixed imports avoid unused-vars lint errors
  • Links render as clickable in VSCode, Zed, and modern IDEs
  • Focus on what TS cannot express: intent, constraints, exceptions
  • See limitations.md for known TypeScript/IDE limitations

Score

Total Score

55/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon