Skip to main content

JSDoc Documentation Guide

Quick Reference for RFC 1002: Comprehensive JSDoc/TSDoc Documentation Standard

This guide provides practical examples for documenting TypeScript/React code in the arolariu.ro frontend.

Quick Start

Basic JSDoc Structure

Every public function, component, and type should have JSDoc:

/**
* One-sentence summary (80 chars max).
*
* @remarks
* Detailed explanation with context.
*
* @param paramName - Description
* @returns Description of return value
*
* @example
* ```typescript
* const result = myFunction('value');
* ```
*/

Common Patterns

React Server Components

/**
* Displays the user's invoice dashboard with real-time updates.
*
* @remarks
* This is a React Server Component that fetches data directly.
* No client-side JavaScript is shipped for this component.
*
* @param props - Component properties
* @returns Server-rendered invoice dashboard
*
* @example
* ```tsx
* export default async function Page() {
* return <InvoiceDashboard userId="123" />;
* }
* ```
*/
export async function InvoiceDashboard(props: DashboardProps): Promise<React.JSX.Element> {
const data = await fetchInvoices(props.userId);
return <div>{/* ... */}</div>;
}

React Client Components

"use client";

/**
* Interactive invoice filter with real-time search and sorting.
*
* @remarks
* This is a Client Component due to:
* - Uses useState for search term
* - Requires onClick handlers
* - Needs immediate user feedback
*
* @param props - Filter configuration
* @returns Interactive filter UI
*
* @example
* ```tsx
* <InvoiceFilter onFilterChange={handleFilter} />
* ```
*/
export function InvoiceFilter(props: FilterProps): React.JSX.Element {
const [searchTerm, setSearchTerm] = useState("");
// ...
}

Custom Hooks

/**
* Manages invoice selection state with multi-select support.
*
* @remarks
* Provides:
* - Select/deselect individual invoices
* - Select/deselect all invoices
* - Persistent selection across re-renders
*
* @param invoiceIds - Available invoice IDs
* @returns Selection state and control functions
*
* @example
* ```typescript
* const {selectedIds, toggleSelection, selectAll} = useInvoiceSelection(ids);
* ```
*/
export function useInvoiceSelection(invoiceIds: string[]): SelectionState {
// ...
}

Server Actions

"use server";

/**
* Updates an invoice and revalidates the cache.
*
* @remarks
* This is a Server Action that:
* - Runs only on the server (never exposed to client)
* - Validates user permissions
* - Revalidates the /invoices path
* - Returns type-safe result
*
* @param formData - Form data containing invoice fields
* @returns Success/error result with updated invoice
*
* @throws {AuthenticationError} If user is not authenticated
* @throws {ValidationError} If invoice data is invalid
*
* @example
* ```typescript
* const result = await updateInvoice(formData);
* if (result.success) {
* toast.success("Invoice updated!");
* }
* ```
*/
export async function updateInvoice(formData: FormData): Promise<ActionResult<Invoice>> {
// ...
}

Utility Functions

/**
* Formats a number as currency with locale support.
*
* @remarks
* - Uses Intl.NumberFormat for locale-aware formatting
* - Falls back to USD if currency is undefined
* - Handles zero, negative, and large numbers correctly
*
* @param amount - Numeric amount to format
* @param currency - ISO 4217 currency code (e.g., "USD", "EUR")
* @param locale - BCP 47 locale string (defaults to "en-US")
* @returns Formatted currency string (e.g., "$123.45")
*
* @example
* ```typescript
* formatCurrency(1234.56, "USD", "en-US"); // "$1,234.56"
* formatCurrency(1234.56, "EUR", "ro-RO"); // "1.234,56 €"
* ```
*/
export function formatCurrency(
amount: number,
currency: string = "USD",
locale: string = "en-US"
): string {
// ...
}

Type Definitions

/**
* Represents a user invoice with payment and item details.
*
* @remarks
* Domain Model:
* - Invoices are immutable after creation (except metadata)
* - Total amount is computed from items (not stored separately)
* - Payment information is optional (unpaid invoices)
*
* @example
* ```typescript
* const invoice: Invoice = {
* id: "inv_123",
* merchantId: "mrc_456",
* items: [{productId: "prod_789", quantity: 2}],
* paymentInformation: {method: PaymentType.CARD},
* metadata: {tags: ["grocery"]},
* };
* ```
*/
export interface Invoice {
/** Unique invoice identifier (format: inv_[a-z0-9]{10}) */
id: string;

/** Merchant who issued this invoice */
merchantId: string;

/** Line items included in this invoice */
items: InvoiceItem[];

/** Payment details (undefined if unpaid) */
paymentInformation?: PaymentInformation;

/** User-defined metadata (tags, notes, etc.) */
metadata: InvoiceMetadata;
}

Context Providers

/**
* Provides theme state (light/dark mode) to the component tree.
*
* @remarks
* Implementation:
* - Persists theme preference to localStorage
* - Syncs with system preferences (prefers-color-scheme)
* - Prevents flash of unstyled content (FOUC)
* - Uses CSS variables for theme values
*
* @param props - Provider configuration
* @returns Theme context provider
*
* @example
* ```tsx
* <ThemeProvider>
* <App />
* </ThemeProvider>
* ```
*
* @see {@link useTheme} for consuming theme context
*/
export function ThemeProvider({children}: {children: React.ReactNode}): React.JSX.Element {
// ...
}

Essential Tags

@remarks - Detailed Explanation

Use for multi-paragraph context, design decisions, trade-offs:

/**
* Lazy-loads the invoice chart component.
*
* @remarks
* Performance Optimization:
* - Reduces initial bundle size by ~150KB
* - Chart only loads when user clicks "View Analytics"
* - Uses React.lazy() with Suspense boundary
* - Shows skeleton loader during chunk download
*
* Trade-offs:
* - Adds ~200ms delay on first chart view
* - Worth it: only 15% of users view analytics
*/
const InvoiceChart = lazy(() => import("./InvoiceChart"));

@param - Parameter Documentation

Include type, purpose, constraints, defaults:

/**
* Filters invoices by date range and merchant.
*
* @param invoices - Array of invoices to filter (must not be empty)
* @param startDate - Filter start date (inclusive, ISO 8601 format)
* @param endDate - Filter end date (inclusive, defaults to today)
* @param merchantId - Optional merchant filter (undefined = all merchants)
* @returns Filtered invoice array (may be empty)
*/
function filterInvoices(
invoices: Invoice[],
startDate: string,
endDate: string = new Date().toISOString(),
merchantId?: string
): Invoice[] {
// ...
}

@returns - Return Value Documentation

Explain what's returned, when undefined/null, edge cases:

/**
* Fetches user invoice by ID.
*
* @param invoiceId - Invoice identifier
* @returns Invoice object if found, null if not found
*
* @throws {AuthenticationError} If user is not logged in
* @throws {NetworkError} If API request fails
*/
async function getInvoice(invoiceId: string): Promise<Invoice | null> {
// ...
}

@example - Usage Examples

Show realistic code samples:

/**
* Debounces a function to limit execution rate.
*
* @example
* Basic usage:
* ```typescript
* const debouncedSearch = debounce((term: string) => {
* console.log("Searching for:", term);
* }, 300);
*
* debouncedSearch("hello"); // Waits 300ms before logging
* ```
*
* @example
* With React state:
* ```typescript
* const handleSearch = debounce((term: string) => {
* setSearchResults(performSearch(term));
* }, 500);
*
* <input onChange={(e) => handleSearch(e.target.value)} />
* ```
*/
function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): T {
// ...
}

@see - Cross-References

Link to related code, RFCs, external docs:

/**
* Creates optimized metadata for SEO and social sharing.
*
* @see {@link RFC1004} for complete metadata architecture
* @see {@link https://nextjs.org/docs/app/api-reference/functions/generate-metadata} Next.js Metadata API
* @see {@link metadata} for base metadata configuration
*/
export function createMetadata(partial: PartialMetadata): Metadata {
// ...
}

Documentation Checklist

Before committing, verify:

  • All public functions have JSDoc
  • JSDoc includes one-sentence summary
  • Complex logic has @remarks explaining "why"
  • All parameters documented with @param
  • Return values documented with @returns
  • At least one @example for non-trivial functions
  • Client Components explain why they're client-side
  • Server Actions document side effects (revalidation, etc.)
  • Error conditions documented with @throws
  • Related code referenced with @see

Anti-Patterns to Avoid

❌ Don't: Obvious Comments

/**
* Gets the user.
* @param userId - The user ID
* @returns The user
*/
function getUser(userId: string): User { }

✅ Do: Add Context

/**
* Fetches user with cached profile data.
*
* @remarks
* - Cached for 5 minutes via React Cache
* - Includes related invoices (eager loading)
* - Returns null for deleted accounts
*
* @param userId - UUID of user to fetch
* @returns User with profile, or null if not found
*/
async function getUser(userId: string): Promise<User | null> { }

❌ Don't: Document Implementation Details

/**
* Uses useState to track the count value and setCount to update it.
*/
const [count, setCount] = useState(0);

✅ Do: Document Purpose

/**
* Tracks number of selected invoices for bulk actions.
*/
const [selectedCount, setSelectedCount] = useState(0);

Quick Reference

Code ElementRequired TagsOptional Tags
FunctionSummary, @param, @returns@remarks, @example, @throws
React ComponentSummary, @param props, @returns@remarks, @example
Custom HookSummary, @param, @returns@remarks, @example
Server ActionSummary, @param, @returns@remarks, @throws, @example
Type/InterfaceSummary, field comments@remarks, @example
UtilitySummary, @param, @returns@remarks, @example, @see

Additional Resources

// was this page useful?