Typedoc

Overview

Our TypeDoc-based parser combines JSDoc comments with TypeScript types to create documentation that matches what you'd see in modern IDEs. This ensures consistent, high-quality type information whether you're viewing it in your development environment or on our documentation sites.

Consider the following example:

export type WeightUnit = "kg" | "lb"
/**
* @public
*/
export interface Dog {
/**
* The age of the dog in human years.
*/
age: number
/**
* The breed of the dog.
*/
breed?: string
/**
* The name of the dog.
*/
name: string
/**
* The weight of the dog. Refer to {@link weightUnit} for unit type information.
*/
weight?: number
/**
* The unit type of the {@link weight} field.
*
* @option `'kg'`: kilograms.
* @option `'lb'`: pounds.
*/
weightUnit?: WeightUnit
}

Our parser uses Typedoc to consume your package's exports. It produces a JSON model with compiled type definitions. We reference the interface's name in our TypeDocProps UI component to render its property documentation table:

<TypeDocProps name="Dog" />

If you've seen QUI documentation before, this table should look familiar.

Name & DescriptionOption(s)Default
The age of the dog in human years.
number
The name of the dog.
string
The breed of the dog.
string
The weight of the dog. Refer to weightUnit for unit type information.
number
The unit type of the weight field.
  • 'kg': kilograms.
  • 'lb': pounds.
'kg' | 'lb'
Type
number
Description
The age of the dog in human years.
Type
string
Description
The name of the dog.
Type
string
Description
The breed of the dog.
Type
number
Description
The weight of the dog. Refer to weightUnit for unit type information.
Type
'kg' | 'lb'
Description
The unit type of the weight field.
  • 'kg': kilograms.
  • 'lb': pounds.

Features

Our type parser recursively expands type details, including references, so your type documentation is easy to consume. Here are the features:

  • JSDoc tag and comment parsing.
  • Property linking to other fields from the same interface.
  • Union expansion.
  • Reference type resolution.
  • Property anchor links, including same-page collision resolution.
  • Pretty type formatting.
  • Required/deprecated property indicators.
  • Mobile-first UI components.

Getting Started

Install Packages

npm i --save-dev @qui/typedoc

Initialize the config

Run the command and follow the prompts to generate the config:

qui-typedoc init

Entry Points

entryPoints refer to the root files or directories from which Typedoc will begin the documentation generation process. These are automatically inferred from your tsconfig file's includes and files fields.

You may optionally define entryPoints in the typedoc configuration file.

QUI Typedoc config

// qui-typedoc.config.ts
import {BuildOptions} from "@qui/typedoc"
export default {
// ...
typedocOptions: {
// optional. If omitted, the entryPoints will be inferred from
// the tsconfig's `includes` and `files` fields.
entryPoints: ["./dist/index.d.ts"],
tsconfig: "tsconfig.typedoc.json",
},
} satisfies BuildOptions

Typedoc tsconfig

// tsconfig.typedoc.json
{
"compilerOptions": {
// ...
},
"include": ["./dist"]
}

Multiple Entry Points

If your library has a local dependency on another package in your workspace, you will need to list that package in your project's entryPoints. Let's illustrate this scenario with an example.

Consider an example project with the following project structure:

packages
base
react
react-docs
  • Assume that react has a dependency on base.
  • Both the react and base projects compile types to their project's dist folder.
  • react-docs contains the @qui/typedoc configuration.

The tsconfig needs to account for both modules:

// packages/react-docs/tsconfig.typedoc.json
{
"compilerOptions": {
// ...
},
"include": ["../base/dist", "../react/dist"]
}

If you're specifying entryPoints in the typedoc config, you will also need to account for each module.

External Reference Types

Types from external modules aren't compiled by default. To include external types, you'll need to do two things:

1. Modify your tsconfig to include the path to the external module's compiled types.
// tsconfig.typedoc.json
{
"compilerOptions": {
// ...
},
"include": ["./dist", "node_modules/<external-package-name>/dist"]
}
2. Enable external module parsing in the typedoc configuration:
// qui-typedoc.config.ts
import {BuildOptions} from "@qui/typedoc"
export default {
// ...
typedocOptions: {
// this is `true` by default
excludeExternals: false,
tsconfig: "tsconfig.typedoc.json",
},
} satisfies BuildOptions

Recommendations and Known Issues

  1. We recommend that you point typedoc at the compiled TypeScript types to improve compilation time. This is why we point our entryPoints at files in dist.
  2. For Angular packages, the output types strip away necessary type information, so we target the package's src root instead, i.e. ./src/index.ts.
  3. Sometimes it is desirable to prevent the expansion of deeply nested types, like an interface that recursively references itself. We've enhanced the @inheritDoc tag for this purpose. Refer to the JSDoc Tags section to learn more.

Reference Types

Ensure References are Exported for Full Expansion

Type definitions (like interfaces or type aliases) used by exported members won't be fully expanded if they're not exported themselves. Consider this example:

interface InternalDefinition {
/**
* Some function
*/
someFn: (args: string) => void
}
/**
* @public
*/
export interface ExternalDefinition {
/**
* Property
*/
property: InternalDefinition
}
  • In this scenario, because InternalDefinition is not exported, the documentation generated for ExternalDefinition.property will only display the type name InternalDefinition.
  • Our tool relies on TypeDoc's analysis of the public API, and unexported types are treated as internal implementation details. To ensure the detailed structure (e.g., { someFn: (args: string) => void }) is shown, you must also export the InternalDefinition interface.

JSDoc Tags

The following tags are enhanced with functionality in the UI.

@default

Use the @default tag to indicate a default value for a property.

/**
* @public
*/
export interface DefaultTagExample {
/**
* Example property.
*
* @default 0
*/
age?: number
}
Name & DescriptionOption(s)Default
Example property.
number
0
Type
number
Default
0
Description
Example property.

@inheritDoc

/**
* @public
*/
export interface Option {
/**
* Unique identifier for the option.
*/
id: string
/**
* Nested options.
*
* @inheritDoc
*/
options?: Option[]
/**
* Option value.
*/
value: string
}
Name & DescriptionOption(s)Default
Unique identifier for the option.
string
Option value.
string
Nested options.
Option[]
Type
string
Description
Unique identifier for the option.
Type
string
Description
Option value.
Type
Option[]
Description
Nested options.

Context is applied conditionally to the inline @link tag.

  • If the link starts with https, it's treated as an external link.
  • If the tag refers to a named property, it's treated as an internal link.
/**
* @public
*/
export interface LinkExample {
/**
* Visit {@link https://google.com this external link} to learn more.
*/
externalLink?: string
/**
* Refer to the {@link externalLink} property.
*/
internalLink?: string
}
Name & DescriptionOption(s)Default
Visit this external link to learn more.
string
Refer to the externalLink property.
string
Type
string
Description
Visit this external link to learn more.
Type
string
Description
Refer to the externalLink property.

@option

Renders a bullet list entry for each option. Useful for documenting union or enum types.

export type WeightUnit = "kg" | "lb"
/**
* @public
*/
export interface OptionTagExample {
/**
* The unit type of the weight field.
*
* @option `'kg'`: kilograms.
* @option `'lb'`: pounds.
*/
weightUnit: WeightUnit
}
Name & DescriptionOption(s)Default
The unit type of the weight field.
  • 'kg': kilograms.
  • 'lb': pounds.
'kg' | 'lb'
Type
'kg' | 'lb'
Description
The unit type of the weight field.
  • 'kg': kilograms.
  • 'lb': pounds.

@see

Use the @see tag to render a separate section of documentation in the JSDoc comment. This is typically used to highlight related types or interfaces.

/**
* @public
*/
export interface SeeTagExample {
/**
* @see {@link someOtherPropExample}
*/
otherPropExample?: string
/**
* Another prop.
*/
someOtherPropExample?: string
}
Name & DescriptionOption(s)Default
string
string
Type
string
Description
Related symbols
Related symbols:
Type
string
Description
Another prop.

@since

The @since tag is used to indicate when a property was added. The default configuration assumes that you have a changelog at /changelog, but this can be modified per instance of TypeDocProps using the changelogPathname prop:

<TypeDocProps changelogPathname="/changelogs/mdx-docs" name="SinceExample" />
/**
* @public
*/
export interface SinceExample {
/**
* Foo.
*
* @since 3.10.0
*/
foo: string
}
Name & DescriptionOption(s)Default
string
Type
string
Description
Foo.

Typedoc Configuration

Default Options

This module ships with reasonable defaults that enable efficient yet comprehensive TypeScript module documentation. You can override these defaults with the typedocOptions config property.

Refer to the corresponding Typedoc documentation for details about each property.

export const defaultOptions: Partial<TypeDocOptions> = {
entryPointStrategy: "expand",
// custom categories that we set to exclude specific properties or interfaces.
excludeCategories: ["react-dom"],
excludeExternals: true,
excludeInternal: true,
excludeNotDocumented: true,
excludeNotDocumentedKinds: [
"Module",
"Namespace",
"Enum",
"Variable",
"Function",
"Class",
"Constructor",
"Property",
"Method",
"CallSignature",
"IndexSignature",
"ConstructorSignature",
"Accessor",
"GetSignature",
"SetSignature",
"Reference",
],
excludePrivate: true,
excludeProtected: true,
logLevel: "Error",
readme: "none",
}