|
1 | | -# Typescript-react-function-component-props-handler [](https://badge.fury.io/js/typescript-react-function-component-props-handler) |
| 1 | +# typescript-react-function-component-props-handler |
2 | 2 |
|
3 | | -Custom handler to proccess react function component props for `react-docgen` package. It allows you to parse props, which are typed as React.functionComponent<props> without rewriting your code. |
| 3 | +[](https://badge.fury.io/js/typescript-react-function-component-props-handler) |
| 4 | +[](https://www.npmjs.com/package/typescript-react-function-component-props-handler) |
| 5 | +[](./LICENSE) |
| 6 | +<!-- Enable this once CI is set up: |
| 7 | +[](https://github.com/Winner95/typescript-react-function-component-props-handler/actions/workflows/ci.yml) |
| 8 | +--> |
4 | 9 |
|
5 | | -## Intro |
| 10 | +Custom handler to **process React function component props** for [`react-docgen`](https://react-docgen.dev/). |
| 11 | +It lets you parse props for components typed as `React.FC<Props>` / `React.FunctionComponent<Props>` **without** rewriting your code. |
6 | 12 |
|
7 | | -React-docgen 5.3.0 allow you to parse React.components and generate documentation. But if you don't explicitly set type of pros parameter, information about props is not visible in output. This custom handler allows you to fix [this problem](https://github.com/reactjs/react-docgen/issues/387). This is one-purpose, zero-dependency project. |
| 13 | +--- |
8 | 14 |
|
9 | | -## Getting started |
| 15 | +## Why this project exists |
10 | 16 |
|
11 | | -### Add nececcary dependencies to your project |
| 17 | +`react-docgen` can parse React components and generate JSON documentation, but for TypeScript projects there’s a common gotcha: |
| 18 | + |
| 19 | +```tsx |
| 20 | +// Button.tsx |
| 21 | +import React from "react"; |
| 22 | + |
| 23 | +export type ButtonProps = { |
| 24 | + /** Text inside the button */ |
| 25 | + label: string; |
| 26 | + /** Whether the button is disabled */ |
| 27 | + disabled?: boolean; |
| 28 | +}; |
| 29 | + |
| 30 | +export const Button: React.FC<ButtonProps> = (props) => ( |
| 31 | + <button disabled={props.disabled}>{props.label}</button> |
| 32 | +); |
| 33 | +``` |
| 34 | + |
| 35 | +With `react-docgen@5.x`: |
| 36 | + |
| 37 | +- If you **don’t** explicitly type the `props` parameter |
| 38 | + (e.g. `({ label }: ButtonProps)`), |
| 39 | +- And instead only type the component as `React.FC<ButtonProps>`, |
| 40 | + |
| 41 | +then the props information is usually **missing** in the generated docs. |
| 42 | + |
| 43 | +This handler: |
| 44 | + |
| 45 | +- Looks at the component’s **function type** (`React.FC<ButtonProps>`) |
| 46 | +- Copies that type onto the **props parameter** in the AST |
| 47 | +- So `react-docgen` can finally “see” your props and emit them in the output. |
| 48 | + |
| 49 | +It’s a small, one-purpose, zero-dependency helper to fix that specific gap. |
| 50 | + |
| 51 | +--- |
| 52 | + |
| 53 | +## Compatibility |
| 54 | + |
| 55 | +| Library version | `react-docgen` | Node | |
| 56 | +| ------------------------- | -------------- | ------ | |
| 57 | +| `1.x` (current) | `5.x` | `>=14` | |
| 58 | +| `2.x` (planned / WIP)`*` | `6.x` | `>=18` | |
| 59 | + |
| 60 | +`*` The roadmap for `2.x` (react-docgen 6 support) is tracked in the repo issues. |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## Installation |
| 65 | + |
| 66 | +Using **yarn**: |
12 | 67 |
|
13 | 68 | ```bash |
14 | 69 | yarn add typescript-react-function-component-props-handler react-docgen |
15 | 70 | ``` |
16 | 71 |
|
17 | | -### Write script for running react-docgen |
| 72 | +Using **npm**: |
| 73 | + |
| 74 | +```bash |
| 75 | +npm install typescript-react-function-component-props-handler react-docgen |
| 76 | +``` |
| 77 | + |
| 78 | +--- |
| 79 | + |
| 80 | +## Quick start (step-by-step) |
| 81 | + |
| 82 | +### 1. Add a component typed as `React.FC` |
| 83 | + |
| 84 | +```tsx |
| 85 | +// src/Button.tsx |
| 86 | +import React from "react"; |
| 87 | + |
| 88 | +export type ButtonProps = { |
| 89 | + /** Text inside the button */ |
| 90 | + label: string; |
| 91 | + /** Whether the button is disabled */ |
| 92 | + disabled?: boolean; |
| 93 | +}; |
| 94 | + |
| 95 | +export const Button: React.FC<ButtonProps> = ({ label, disabled }) => ( |
| 96 | + <button disabled={disabled}>{label}</button> |
| 97 | +); |
| 98 | +``` |
18 | 99 |
|
19 | | -Add the following content to the file: |
| 100 | +Note: The parameter itself is **not** explicitly typed, only the component is. |
| 101 | + |
| 102 | +--- |
| 103 | + |
| 104 | +### 2. Create a small docgen script |
20 | 105 |
|
21 | 106 | ```js |
| 107 | +// docgen.js |
| 108 | +const fs = require("fs"); |
| 109 | +const path = require("path"); |
| 110 | +const reactDocs = require("react-docgen"); |
| 111 | + |
| 112 | +// The custom handler from this package |
| 113 | +const setParamsTypeDefinitionFromFunctionType = |
| 114 | + require("typescript-react-function-component-props-handler"); |
22 | 115 |
|
23 | | -const reactDocs = require('react-docgen'); |
| 116 | +const filePath = process.argv[2]; |
| 117 | +if (!filePath) { |
| 118 | + console.error("Usage: node docgen.js <path-to-component>"); |
| 119 | + process.exit(1); |
| 120 | +} |
24 | 121 |
|
25 | | -const setParamsTypeDefinitionFromFunctionType = require('typescript-react-function-component-props-handler'); |
| 122 | +const source = fs.readFileSync(path.resolve(filePath), "utf8"); |
26 | 123 |
|
27 | 124 | const doc = reactDocs.parse( |
28 | | - source, |
29 | | - null, |
30 | | - [setParamsTypeDefinitionFromFunctionType, ...reactDocs.defaultHandlers], |
31 | | - null |
| 125 | + source, |
| 126 | + null, |
| 127 | + [setParamsTypeDefinitionFromFunctionType, ...reactDocs.defaultHandlers], |
| 128 | + null |
32 | 129 | ); |
33 | 130 |
|
| 131 | +console.log(JSON.stringify(doc, null, 2)); |
34 | 132 | ``` |
35 | 133 |
|
36 | | -**Note:** `source` is a path to your component to parse. |
| 134 | +--- |
| 135 | + |
| 136 | +### 3. Run the script |
| 137 | + |
| 138 | +```bash |
| 139 | +node docgen.js src/Button.tsx |
| 140 | +``` |
| 141 | + |
| 142 | +You should now see your props in the JSON output, even though `props` wasn’t explicitly typed on the parameter. |
| 143 | + |
| 144 | +--- |
| 145 | + |
| 146 | +### 4. Example output (trimmed) |
| 147 | + |
| 148 | +```json |
| 149 | +{ |
| 150 | + "displayName": "Button", |
| 151 | + "props": { |
| 152 | + "label": { |
| 153 | + "type": { "name": "string" }, |
| 154 | + "required": true, |
| 155 | + "description": "Text inside the button" |
| 156 | + }, |
| 157 | + "disabled": { |
| 158 | + "type": { "name": "boolean" }, |
| 159 | + "required": false, |
| 160 | + "description": "Whether the button is disabled" |
| 161 | + } |
| 162 | + } |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +--- |
| 167 | + |
| 168 | +## Usage options |
| 169 | + |
| 170 | +### 1. Programmatic usage (Node script) |
| 171 | + |
| 172 | +This is the core way to use the handler: |
| 173 | + |
| 174 | +```js |
| 175 | +const reactDocs = require("react-docgen"); |
| 176 | +const setParamsTypeDefinitionFromFunctionType = |
| 177 | + require("typescript-react-function-component-props-handler"); |
| 178 | + |
| 179 | +const doc = reactDocs.parse( |
| 180 | + source, // string with your component source |
| 181 | + null, // resolver (null -> default) |
| 182 | + [setParamsTypeDefinitionFromFunctionType, ...reactDocs.defaultHandlers], |
| 183 | + null |
| 184 | +); |
| 185 | +``` |
| 186 | + |
| 187 | +> `source` should be the component source code (e.g. read from a `.tsx` file). |
| 188 | +
|
| 189 | +--- |
| 190 | + |
| 191 | +## What code examples are covered |
| 192 | + |
| 193 | +The handler is focused on **function components typed via React’s function component types**, for example: |
| 194 | + |
| 195 | +- `const Button: React.FC<ButtonProps> = (props) => { … }` |
| 196 | +- `const Button: React.FunctionComponent<ButtonProps> = (props) => { … }` |
| 197 | +- Both named and default exports |
| 198 | +- Components where props are **not** explicitly typed at the parameter level |
| 199 | + |
| 200 | +Things this handler **does not** try to solve: |
| 201 | + |
| 202 | +- Class components (already handled by `react-docgen`) |
| 203 | +- Function components where the parameter is already explicitly typed |
| 204 | +- Non-TypeScript code |
| 205 | + |
| 206 | +If you hit a pattern that doesn’t work as expected, feel free to open an issue with a minimal repro. |
| 207 | + |
| 208 | +--- |
| 209 | + |
| 210 | +## Disclaimer |
| 211 | + |
| 212 | +This library is provided **“as is”**, without warranty of any kind. |
| 213 | +Use it at your own risk. The author(s) are **not responsible** for any issues, data loss, or production incidents resulting from its use. |
| 214 | + |
| 215 | +This package is a small helper for `react-docgen`. |
| 216 | +It is **not** an officially supported product of any company I work or have worked for. |
| 217 | + |
| 218 | +--- |
| 219 | + |
| 220 | +## Support & responsibility |
| 221 | + |
| 222 | +This is a best-effort open source project maintained in personal spare time. |
| 223 | + |
| 224 | +- I’ll try to review issues and PRs. |
| 225 | +- I can’t guarantee response times, feature work, or fixes for every edge case. |
| 226 | +- Please evaluate the library and decide if it’s suitable for your project before using it in production. |
| 227 | + |
| 228 | +Contributions (bug reports, failing test cases, docs improvements) are very welcome. |
| 229 | + |
| 230 | +--- |
| 231 | + |
| 232 | +## Live examples |
| 233 | + |
| 234 | +These sandboxes show concrete configurations with and without this handler. |
| 235 | + |
| 236 | +- **react-docgen@6 – config without this handler (props NOT shown)** |
| 237 | + https://codesandbox.io/p/sandbox/initial-600-beta22-config-prototype-with-not-showing-props-react-docgen-kwz72 |
| 238 | + |
| 239 | +- **react-docgen@6 – config with this handler (props shown)** |
| 240 | + https://codesandbox.io/p/sandbox/initial-600-beta22-config-working-prototype-with-showing-props-react-docgen-ftvf2 |
| 241 | + |
| 242 | +> For the StackBlitz examples below, open the built-in terminal and run `node index.js`. |
| 243 | +
|
| 244 | +- **StackBlitz demo #1 (react-docgen setup, baseline)** |
| 245 | + https://stackblitz.com/edit/stackblitz-starters-ry91wvpz?file=index.js |
37 | 246 |
|
38 | | -## What code-examples are covered |
| 247 | +- **StackBlitz demo #2 (variant with this handler wired in)** |
| 248 | + https://stackblitz.com/edit/stackblitz-starters-2w1zpcnx?file=index.js |
39 | 249 |
|
40 | | -Most of general and corner-cases for `React.functionComponents` were covered. |
| 250 | +--- |
41 | 251 |
|
42 | 252 | ## Useful links |
43 | 253 |
|
44 | | -You can test your components in these online services: |
| 254 | +You can explore and debug components & ASTs with: |
45 | 255 |
|
46 | | -* [React-docgen: playground](https://reactcommunity.org/react-docgen/) |
47 | | -* [TypeScript AST Viewer](https://ts-ast-viewer.com/) |
48 | | -* [AST Explorer](https://astexplorer.net/) |
| 256 | +- [`react-docgen` playground](https://react-docgen.dev/playground) |
| 257 | +- [TypeScript AST Viewer](https://ts-ast-viewer.com/) |
| 258 | +- [AST Explorer](https://astexplorer.net/) |
0 commit comments