Skip to content

Repository files navigation

type-to-table

npm version types CI license

Type in, table out. 📐

Your types are already documented — in the JSDoc above each field. type-to-table reads a TypeScript interface or object type, resolves it with the real TypeScript checker, and writes a markdown table straight into your README. Re-run it after every change to keep the table in sync with the type. Works on any plain type — options bags, config objects, API response shapes — no React, no rendering component, no runtime values required.

React component props are a common special case (props need a mounted-looking component to resolve against, and there's no defaultProps to read a default from). That case gets its own entry point: type-to-table/react, powered by react-docgen-typescript. It's an optional peer dependency — install it only if you use that subpath, and it's never pulled into the base type-to-table import.

Why not just write it by hand?

type-to-table hand-maintained table Storybook autodocs
Source of truth the type + its JSDoc whatever you remember to update the type, via a running Storybook
Drift none — re-run after any type change guaranteed, eventually none, but only inside Storybook
Output one markdown table, in your README markdown, wherever you put it a browsable UI, not your README
Setup an exported type + JSDoc @default tags none Storybook + a story per component
Scope any interface/type, or React props via a subpath anything you write by hand React components only

Use Storybook when you want an interactive playground. Reach for this when you just want the README table that's already true.

What's new

Version Highlights
2.1.0 TypeScript types no longer require React
2.0.0 typeGet/typeWrite for plain interfaces and types — no React needed. React props tables moved to the type-to-table/react subpath; react-docgen-typescript is now an optional peer dependency.
1.0.1 Internal changes only

Full history in CHANGELOG.md.

Install

bun add -D type-to-table   # npm / pnpm / yarn all fine

Using the React subpath (type-to-table/react)? Also install its peer dependency:

bun add -D react-docgen-typescript

Quick start

Write JSDoc above each field, @default included:

// src/config.ts
export interface ServerOptions {
  /** Port to listen on. @default 3000 */
  port?: number;
  /** Enables verbose request logging. @default false */
  verbose?: boolean;
  /** Path to the TLS certificate. No default — required in production. */
  certPath: string;
}

Drop a pair of marker comments into your README — type-to-table replaces whatever sits between them, so name the tag whatever you like. Then run:

bun run docs:type -- src/config.ts ServerOptions OPTIONS-TABLE

The content between <!-- OPTIONS-TABLE:START --> / <!-- OPTIONS-TABLE:END --> gets replaced with the generated table.

The rules

1 · @default is the only source of the Default column. A type has no runtime value, so without a @default X tag in the JSDoc, the Default column is just empty for that field.

2 · One pass, safe by construction. | gets escaped before a row is built, so a description containing a pipe (or a union type like string | number) can't break the table. Long descriptions can be capped with maxDescriptionLength.

3 · React props need type-to-table/react instead. react-docgen-typescript resolves props from a real component using the type — FC<Props>, a class component, forwardRef, etc. — not from the type declaration alone. A type with nothing rendering it has nothing to anchor resolving on, and tttGet throws No component found. See React props tables below.

API

import { typeGet, typeWrite } from "type-to-table";

typeGet(filePath, typeName, options?)

Parses filePath, finds the interface or object type alias named typeName, and returns its fields as a markdown table (Field | Type | Default | Description).

Option Type Default What it does
maxDescriptionLength number Truncates each field's description to this many characters, with .

typeWrite(filePath, typeName, readmePath, tag, options?)

Calls typeGet(filePath, typeName, options) and writes the result into readmePath between <!-- {tag}:START --> / <!-- {tag}:END --> (via taglify's taglWrite). Returns whether the file changed.

CLI

bun run docs:type -- path/to/file.ts TypeName TAG-NAME

Writes into ./README.md. Wraps typeWrite — see scripts/docs-type.ts if you need a different target file.

React props tables

import { tttGet, tttWrite } from "type-to-table/react";

Same idea, specialized for React component props via react-docgen-typescript — needs an exported component (FC<Props>, class, forwardRef, …) using the props type to anchor resolving on; see The rules above.

// examples/Button.tsx
import type { FC } from "react";

export type ButtonProps = {
  /** Button label. */
  label: string;
  /** Visual style. @default 'primary' */
  variant?: "primary" | "secondary";
  /** Disables interaction. @default false */
  disabled?: boolean;
};

export const Button: FC<ButtonProps> = ({ label }) => label;
bun run docs:props -- examples/Button.tsx

Writes into ./README.md, tag PROPS-TABLE — see Props table below, generated from this exact file.

tttGet(filePath, options?)

Option Type Default What it does
componentName string Which component to document when the file exports more than one.
maxDescriptionLength number Truncates each prop's description to this many characters, with .
parserOptions ParserOptions Passed straight through to react-docgen-typescript's parse() — e.g. componentNameResolver, customComponentTypes.

tttWrite(filePath, readmePath, options?)

Calls tttGet(filePath, options) and writes the result into readmePath between the tag's marker comments. Returns whether the file changed.

CLI

bun run docs:props -- path/to/Component.tsx [componentName]

Props table

Generated by running bun run docs:props -- examples/Button.tsx against examples/Button.tsx — this section is the React subpath's own test case.

Prop Type Default Description
label string Button label.
variant? "primary" | "secondary" 'primary' Visual style.
disabled? boolean false Disables interaction.

Development

bun install
bun run test        # bun test
bun run typecheck
bun run build       # vite → dist/
bun run format      # biome check --write

License

MIT © jayF0x

About

Turns a TypeScript type's JSDoc into a markdown table so your docs never fall out of sync with the code. React props tables via type-to-table/react.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages