Storybook Button 组件 Props 声明完整指南:跨框架 JSDoc 写法与 argTypes 自动生成 Storybook Button 组件 Props 声明完整指南跨框架 JSDoc 写法与 argTypes 自动生成读完这份指南你能为 React、Angular、Vue 3、Svelte、Web ComponentsLit五类技术栈各写出一份开箱即文档的 Button 组件Props 类型、默认值、必填语义和 JSDoc 说明一次到位让 Storybook 的 Controls 面板与 Docs ArgsTable 无需手写配置直接生效并顺带掌握写完组件后第一个 CSF Story 的 meta 写法。一、声明 component: Button 之后Controls 为什么会自动长出来打开任何一个 Storybook 文档页右侧的 Controls 面板并不是谁手动配置的开关和文本框集合。触发链条只有两跳你在.stories文件的 meta 中写下component: Button构建期对应框架的 docgen 工具解析Button源码把每个属性的类型、默认值、是否必填、注释文字整理成一份argTypes结构预览端拿到这份结构后按类型映射控件boolean渲染成开关、string渲染成文本框、默认值填进输入框注释文字渲染成控件旁的说明。拿仓库里的真实产物对照。docs/_snippets/button-component-with-proptypes.md 这个片段定义的 Button 只有两个属性isDisabled、content构建后 Storybook 会产出类似 docs/_snippets/storybook-generated-argtypes.md 所示的结构// 由 docgen 自动生成的 argTypes 长这样节选 const argTypes { label: { name: label, type: { name: string, required: false }, // 类型 → 决定控件形态 defaultValue: Hello, // 默认值 → 填进输入框 description: demo description, // JSDoc → 说明文字 table: { type: { summary: string } }, control: { type: text }, // string → 文本框 }, };换句话说type决定控件形态、defaultValue决定初始值、description决定面板文案——这三个字段几乎全部由你在组件里写的声明产生。这就是组件即文档的全部秘密。二、argTypes 是怎么被生成的五条 docgen 链路逐条看在动手写代码之前先弄清每个框架从哪读数据。你写的声明只有落在对应工具的读取范围内才会进入argTypes。Reactreact-docgen 读 propTypes插件读 TS interface声明位置JS 版读Button.propTypesTS 版读ButtonPropsinterface。最小代码工具实际读取的对象Button.propTypes { isDisabled: PropTypes.bool.isRequired, // react-docgen 提取类型 required content: PropTypes.string.isRequired, };要点Vite 框架同时挂了react-docgen处理 JS/PropTypes与joshwooding/vite-plugin-react-docgen-typescript处理 TS interface自定义逻辑在 code/frameworks/react-vite/src/plugins/ 的docgen-handlers与docgen-resolver.ts中Webpack 侧则由 code/presets/react-webpack/ 引入storybook/react-docgen-typescript-plugin。易错点propTypes若挂在未导出的内部组件上resolver 找不到ButtonargTypes 直接为空。AngularCompodoc 读 Input 字段与 JSDoc声明位置类上带Input()装饰的公开字段。最小代码export class ButtonComponent { /** * Checks if the button should be disabled */ Input() isDisabled: boolean; // 注释 类型都进入 __docgenInfo }要点code/frameworks/angular/ 通过storybook/angular-compodoc执行 Compodoc 生成__docgenInfoAngular-Vite 则在 code/frameworks/angular-vite/ 内置了internal/docgen-worker独立解析。易错点没有Input()装饰器的公开字段会被 Compodoc 当作内部成员跳过Controls 里直接消失。Vue 3vue-docgen-api 读 props 选项对象声明位置export default的props选项含type/default/required。最小代码props: { isDisabled: { type: Boolean, default: false }, // 三要素都在这里 label: { type: String, default: One, required: true }, },要点渲染器依赖vue-docgen-api入口在 code/renderers/vue3/src/docgen/build-docgen.ts经docgen-worker把结果挂到组件__docgenInfo再转 argTypes。易错点script setup里用对象字面量声明 props 时vue-docgen 的解析能力弱于 Options API文档字段可能不完整。Svelte读 export let 变量与变量上的 JSDoc声明位置script内export let导出的变量。最小代码script /** * Disable the button * required */ export let disabled false; // 变量名→属性名初值→默认值 /script要点code/renderers/svelte/src/extractArgTypes.ts 与extractComponentDescription.ts负责从组件注释中提取属性元信息供 Svelte CSF 的defineMeta消费。易错点变量必须export普通let不会被识别为 prop。Web Components / Lit读类上方 JSDoc 与属性声明声明位置类上方的propJSDoc 块加上static get properties()JS或property()TS。最小代码/** * prop {string} content - The display label of the button * prop {boolean} isDisabled - Checks if the button should be disabled * tag custom-button */ export class CustomButton extends LitElement { /* ... */ }要点code/renderers/web-components/ 的预览端直接从这份注释构建 argTypestag决定文档中标注的注册名。易错点prop的属性名拼错后不会报错只是该属性在面板里查无此名。三、Props 声明四要素五类技术栈横向怎么写搞清数据来源后正文只回答一个问题同一个 Button四类声明要素在各技术栈分别写在哪、怎么写。 要素一类型——它决定 Controls 长出什么控件技术栈类型写在哪儿本例中的写法React (JS)propTypes值PropTypes.bool/PropTypes.stringReact (TS)interface 字段类型isDisabled: boolean/content: stringAngularInput()字段的 TS 类型isDisabled: booleanVue 3 (JS/TS)props的运行时typetype: Boolean/type: StringSvelteexport let初值推断 false推出 booleanLit (JS)static properties的typecontent: { type: String }Lit (TS)字段 TS 类型 property()content?: string两个值得记住的行为boolean一律映射为开关控件所以布尔属性别图省事声明成string否则面板会变成文本框Lit 的type: Boolean还负责属性反射时的类型转换模板里配合?disabled${...}布尔绑定使用。要素二默认值——四个不同的落点技术栈默认值写法本例取值React (JS)无该片段未提供交由调用方传—React (TS)解构参数初值isDisabled false, content Angular字段初始化片段未写惯例写isDisabled falseVue 3default字段default: false/default: OneSvelteexport let初值disabled false, content Lit (JS)构造函数赋值this.content OneLit (TS)字段初始化content?: string One规则只有一条你写在哪docgen 就从哪读。Vue 写default就进table.defaultValueLit JS 写构造函数赋值读到的也是构造期的赋值而 React JS 片段干脆不给默认值面板输入框就是空的——这不是 bug是没有声明就没有默认值的诚实体现。要素三必填语义——五套互不兼容的写法技术栈表达必填的方式表达可选的方式React (JS).isRequired去掉.isRequiredReact (TS)字段不带?字段加?AngularJSDoc 标记required见 button-implementation.md 的 Angular 版去掉标记Vue 3required: true去掉该字段SvelteJSDoc 标记required去掉标记Lit无原生机制靠默认值约定同左注意 Svelte 与 Angular 的required是注释级约定运行时不强制但 docgen 会把它转成type.required: true最终反映在 Docs 表格的必填列。而 TS 侧React interface、Lit 装饰器字段的必填判断直接来自?有无改一个字符就能切换语义。要素四说明文本——注释位置决定 description 有无技术栈注释写在哪进入哪个字段React (JS)propTypes每项上方descriptionReact (TS)interface 字段上方descriptionAngularInput()字段上方descriptionVue 3props每项上方descriptionSvelteexport let变量上方descriptionLit (JS/TS)类上方prop ... - 说明descriptionLit 是唯一例外注释不在字段级而在类级格式是prop {类型} 名称 - 说明文字破折号后到行尾的内容就是该属性的描述。其余五处都遵循同一条物理规律注释块必须紧邻声明、且中间没有空行否则 react-docgen 等工具会把它当作游离注释丢弃面板说明随之消失。四、差异与易错点专区跨框架阅读时最容易踩的坑⚠️ 坑一同一个 Button四个属性名对照片段源码会发现命名并不统一React / Angular / Lit禁用开关叫isDisabled文案叫contentVue 3文案叫label模板里渲染{{ label }}Svelte禁用开关叫disabled文案叫content。后果很具体Controls 面板的列名、Docs ArgsTable 的第一列、.stories里args的键名都会跟着变。如果你把一份Button.stories从 React 项目拷到 Svelte 项目args: { isDisabled: ... }会整体对不上Story 直接渲染默认值。迁移前先做一次属性名映射别先调配置。坑二Vue 片段里required: true与default并存JS 版Button.vue的isDisabled同时写了default: false和required: true——语义自相矛盾既然必填默认值何时有用。而它的 TS 版删掉了required: true只留default变成了可省略、缺省为 false。两个文件描述的其实是两种不同的 props 契约。真实项目二选一要么必填删default要么可省删required并让table.defaultValue与运行行为一致。坑三Svelte 片段中的script/闭合笔误docs/_snippets/button-component-with-proptypes.md 的 Svelte 代码块末尾写的是script/这是原文的笔误——Svelte 编译器要求/script显式闭合写成自闭合会直接编译报错。照抄片段到自己项目前先把这一行修正。坑四其他三个小细节Angular 选择器selector: my-button必须是连字符双词写成button会与原生标签冲突并被编译器拒绝Vue 单字组件名片段用name: button会被vue/multi-word-component-names规则告警——button-implementation.md 的 TS 版示范了用eslint-disable-next-line注释抑制的写法新代码建议直接改名Vue 片段的setup是占位props reactive(props)后返回空对象实际未暴露任何绑定抄走这段请连同注释即说明的意图一起判断别把占位逻辑当最佳实践。五、Props 声明自检清单提交 .stories 之前过一遍写完组件、写 Story 之前逐条核对✅ 每个属性都有机器可读的类型来源PropTypes.xxx、TS 字段类型、type: Boolean、property()没有裸传的无名参数✅ 声明的默认值与运行期真实回退值一致解构初值 /default/ 构造函数赋值三处对得上✅ 必填语义用该框架的原生表达没有跨框架照搬TS 里别写required: true字符串Vue 里别依赖?✅ 每个属性的 JSDoc 紧邻声明上方、无空行分隔Lit 场景确认类级prop名称与属性名逐字一致✅ 布尔属性声明为boolean/Boolean这样 Controls 才会渲染开关而不是文本框✅ 属性名在组件、Story、args 三处拼写统一避免面板列名与 args 键错位。六、下一步CSF meta 如何消费这些元信息自检通过后组件声明里的全部元信息会在.stories文件被一次性激活。以 React 为例的最小 meta跨框架版本见 button-story-matching-argtypes.md// filename: Button.stories.ts import type { Meta } from storybook/react; import { Button } from ./Button; const meta { component: Button, // 这一行触发 docgen 产物与 Story 的绑定 parameters: { actions: { argTypesRegex: ^on.* }, // onXxx 属性自动接入 Actions 面板 }, } satisfies Metatypeof Button; export default meta; // 之后每个 Story 只需给 args控件列由 argTypes 自动生成 export const Default { args: { isDisabled: false, content: Hello }, };三个消费行为值得明确component: Button是唯一的点火开关——缺了它前面所有 JSDoc 与类型声明都不会进入面板args提供初始值argTypes 决定控件形态与说明两者在 Controls 面板汇合改动任一控件Story 实时重渲染若组件含onClick之类事件属性argTypesRegex: ^on.*会把它们接入 Actions 面板记录调用详情机制详见 docs/essentials/actions.mdx。对照 button-story-with-args.md 与 docs/writing-stories/args.mdx你可以继续把isDisabled/content这两个属性展开成带分组、带默认参数的完整 Story。至此整条链路闭环声明四要素 → docgen 生成 argTypes → meta 绑定组件 → Controls 与 Docs 自动呈现。组件写得越规范面板就越不用手工维护——这正是把 Props 声明当文档工程来做的好处。创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考