TSDoc formatting rules
Rules and changes made to source files so TypeDoc renders correctly. Applies to
typedoc@0.28 + typedoc-plugin-markdown@4.10.
Config (typedoc.json)
{
"plugin": ["typedoc-plugin-markdown"],
"entryPoints": ["./src/types/err.ts", ...],
"out": "docs/api",
"outputFileStrategy": "modules",
"entryFileName": "README.md",
"excludePrivate": true,
"excludeInternal": true
}Key decisions:
entryPoints— individual source files, not the barrelindex.ts. Using the barrel collapses everything into one file.outputFileStrategy: "modules"— one markdown file per source module.entryFileName: "README.md"— the generated overview/index isdocs/api/README.md(notindex.md), consistent with GitHub directory browsing conventions.excludeInternal: true— hides members tagged@internal. See the overload rule below for how this interacts with TypeScript overloads.
Rules
1. Module naming — require @module <name>
TypeDoc derives output filenames from the module name. Without an explicit @module
tag, modules in subdirectories get a path-prefixed filename (types.outcome.md
instead of outcome.md).
Every source file must have a standalone module comment with @module:
/**
* Module description text.
*
* @module outcome
*/The @module tag must appear in a free-floating comment — one not immediately
followed by a declaration. Placing it at the end of the file-level introductory
block is the standard pattern.
Files and their required tags:
| File | Tag |
|---|---|
src/types/err.ts | @module err |
src/types/outcome.ts | @module outcome |
src/utils/format_dt.ts | @module format_dt |
src/utils/logger.ts | @module logger |
2. No @fileoverview — use plain description text
@fileoverview is a JSDoc convention but TypeDoc does not recognise it and
emits a warning. TypeDoc automatically uses the text content of a free-floating
module-level comment as the module description — no tag is needed.
Before (produces warning):
/**
* @fileoverview Error-as-value implementation for TypeScript applications.
*
* This module provides...
*
* @module err
*/After (no warning):
/**
* Error-as-value implementation for TypeScript applications.
*
* This module provides...
*
* @module err
*/3. Overload implementations — use /* */ not /** */
TypeDoc’s excludeInternal: true operates at the symbol level, not the
signature level. When the implementation signature of an overloaded method carries
@internal in a JSDoc block comment (/** ... */), TypeDoc excludes the entire
method — including all public overload signatures.
Fix: change the JSDoc block comment (/** */) on implementation signatures to a
regular block comment (/* */). The @internal tag inside a non-JSDoc comment is
invisible to TypeDoc.
Before — all overloads hidden from docs:
defaultTo(fallback: T): T;
defaultTo(handler: (error: Err) => T): T;
defaultTo(fallback: T, asValue: true): T;
/**
* Implementation for defaultTo overloads.
* @internal
*/
defaultTo(fallbackOrHandler: T | ((error: Err) => T), asValue?: boolean): T {After — public overloads visible, implementation hidden:
defaultTo(fallback: T): T;
defaultTo(handler: (error: Err) => T): T;
defaultTo(fallback: T, asValue: true): T;
/* Implementation for defaultTo overloads. */
defaultTo(fallbackOrHandler: T | ((error: Err) => T), asValue?: boolean): T {This pattern was applied to four methods in src/types/outcome.ts:
| Method | Location |
|---|---|
Outcome.err() | static factory |
Outcome.defaultTo() | instance method |
Outcome.pipe() | instance method |
Outcome.pipeAsync() | instance method |
private members are unaffected — TypeDoc excludes them via excludePrivate: true regardless of @internal. The @internal tag on private constructors and
private static methods is harmless but redundant.
Layout
docs/
├── api/ ← generated by `bun run gen_docs` (do not edit)
│ ├── README.md ← module index
│ ├── err.md
│ ├── format_dt.md
│ ├── logger.md
│ └── outcome.md
├── err.md ← manual reference (hand-maintained)
├── format_dt.md
├── logger.md
├── logging_guide.md
├── outcome.md
└── tsdoc_guide.md ← this fileThe docs/api/ directory is fully regenerated on every gen_docs run. Manual
docs in docs/ root are independent and unaffected.