React TypeScript Docgen Parser
This library, `react-docgen-typescript`, provides a robust parser for extracting documentation information from React components written in TypeScript. It analyzes TypeScript files to generate documentation data, similar to how `react-docgen` works for JavaScript components with `propTypes`. The current stable version is 2.4.0, with releases occurring semi-frequently, indicating active maintenance and feature development based on recent changelogs. Its primary differentiator is its native support for TypeScript, allowing it to correctly interpret complex type definitions, interfaces, and generics to generate detailed prop tables, including descriptions, types, and default values. It is often used in conjunction with tools like React Styleguidist to automatically generate component documentation.
Common errors
-
TypeError: (tag.text || "").trim is not a function
cause This error typically occurred in versions prior to 2.0.0 due to an issue with how JSDoc tag text was processed, where the 'text' property could be null or undefined.fixUpgrade 'react-docgen-typescript' to version 2.0.0 or newer to resolve this bug, which included fixes for tag text handling. -
Cannot read property 'length' of undefined
cause This often indicates an issue in older versions (pre-2.0.0) where internal data structures for declarations or other parsed elements were unexpectedly undefined, leading to runtime errors when trying to access properties like 'length'.fixUpgrade 'react-docgen-typescript' to version 2.0.0 or newer, as this was addressed in fixes for that major release. -
Property 'declarations' of 'PropItem' is undefined or has no 'length' property
cause In older versions, particularly around 1.20.5, specific scenarios could lead to 'declarations' being undefined, causing runtime errors when attempting to access its 'length' property.fixEnsure you are using 'react-docgen-typescript' version 1.20.5 or newer, or ideally any 2.x version, where these edge cases were resolved. -
trimFileName no longer works in a monorepo
cause This was a specific bug in versions prior to 2.2.2 where the 'trimFileName' logic failed to correctly process file paths when used within a monorepo setup.fixUpgrade 'react-docgen-typescript' to version 2.2.2 or higher to fix the 'trimFileName' functionality in monorepos.
Warnings
- breaking Version 2.0.0 introduced a breaking change by requiring TypeScript 4.3 or newer due to the use of a new TypeScript API function. Projects using older TypeScript versions will encounter errors.
- breaking Starting from version 2.4.0, the 'esModuleInterop' compiler option is set as a default configuration during parsing when using `parse` or `withDefaultConfig`. If your project relies on specific 'esModuleInterop' behavior that conflicts with this default (e.g., explicit `false`), you might experience changes in how imports are resolved during parsing.
- gotcha The library depends on 'typescript' as a peer dependency. Incompatible 'typescript' versions (e.g., using an older version than '>= 4.3.x' with `react-docgen-typescript` v2.0.0+) can lead to parsing errors or unexpected behavior during documentation generation.
Install
-
npm install react-docgen-typescript -
yarn add react-docgen-typescript -
pnpm add react-docgen-typescript
Imports
- parse
const docgen = require('react-docgen-typescript'); docgen.parse('./path/to/component')import { parse } from 'react-docgen-typescript' - withDefaultConfig
const docgen = require('react-docgen-typescript'); docgen.withDefaultConfig(options)import { withDefaultConfig } from 'react-docgen-typescript' - withCustomConfig
const docgen = require('react-docgen-typescript'); docgen.withCustomConfig('./tsconfig.json', options)import { withCustomConfig } from 'react-docgen-typescript' - ComponentDoc
import type { ComponentDoc } from 'react-docgen-typescript'
Quickstart
import { withCustomConfig } from 'react-docgen-typescript';
import * as fs from 'fs';
import * as path from 'path';
// Define a dummy component file for demonstration
const componentCode = `
import React from 'react';
interface ButtonProps {
/**
* The text content of the button.
*/
label: string;
/**
* Is this the principal call to action on the page?
* @default false
*/
primary?: boolean;
/**
* What background color to use
*/
backgroundColor?: string;
/**
* How large should the button be?
* @default 'medium'
*/
size?: 'small' | 'medium' | 'large';
/**
* Optional click handler
*/
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
/**
* A primary button component
*/
export const Button: React.FC<ButtonProps> = ({
label,
primary = false,
backgroundColor,
size = 'medium',
onClick,
}) => {
const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
return (
<button
type="button"
className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}
style={{ backgroundColor }}
onClick={onClick}
>
{label}
</button>
);
};
`;
const tempDir = path.join(__dirname, 'temp');
if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir);
}
const tempComponentPath = path.join(tempDir, 'Button.tsx');
fs.writeFileSync(tempComponentPath, componentCode);
// Create a basic tsconfig.json for the parser
const tsconfigPath = path.join(tempDir, 'tsconfig.json');
fs.writeFileSync(tsconfigPath, JSON.stringify({
compilerOptions: {
jsx: "react",
module: "ESNext",
target: "ESNext",
esModuleInterop: true,
strict: true,
skipLibCheck: true,
},
include: [tempDir + "/**/*"]
}, null, 2));
const parser = withCustomConfig(tsconfigPath, {
shouldExtractLiteralValuesFromEnum: true,
propFilter: {
skipPropsWithoutDoc: true,
},
});
try {
const componentDocs = parser.parse(tempComponentPath);
console.log(JSON.stringify(componentDocs, null, 2));
} catch (error) {
console.error("Error parsing component:", error);
} finally {
// Clean up temporary files
fs.unlinkSync(tempComponentPath);
fs.unlinkSync(tsconfigPath);
fs.rmdirSync(tempDir);
}