3.2.1 积木的插槽怎么设计——Props 类型定义
一句话破题
Props 是组件的"接口契约",定义了外部可以传入什么数据、什么格式、是否必填。
核心价值
好的 Props 设计让组件既灵活又安全。TypeScript 的类型系统能在编译时捕获错误,让 AI 生成的代码更可靠,也让你在 Review 时更有把握。
Props 基础
定义组件 Props:
tsx
// 方式一:interface(推荐)
interface ButtonProps {
label: string // 必填
variant?: 'primary' | 'secondary' // 可选,联合类型
disabled?: boolean // 可选
onClick?: () => void // 可选,回调函数
}
// 方式二:type
type ButtonProps = {
label: string
variant?: 'primary' | 'secondary'
}
// 使用 Props
function Button({ label, variant = 'primary', disabled = false, onClick }: ButtonProps) {
return (
<button
className={`btn-${variant}`}
disabled={disabled}
onClick={onClick}
>
{label}
</button>
)
}默认值设置
两种方式设置默认值:
tsx
// 方式一:解构时设置(推荐)
function Card({ title, size = 'medium' }: CardProps) {
// ...
}
// 方式二:defaultProps(不推荐,已过时)
Card.defaultProps = {
size: 'medium'
}children Props
children 是特殊的 prop,用于传递嵌套内容:
tsx
interface CardProps {
title: string
children: React.ReactNode // 可以是任何可渲染内容
}
function Card({ title, children }: CardProps) {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-body">{children}</div>
</div>
)
}
// 使用
<Card title="用户信息">
<p>姓名:张三</p>
<p>年龄:25</p>
</Card>常用 Props 类型
| 类型 | 用途 | 示例 |
|---|---|---|
string | 文本 | title: string |
number | 数值 | count: number |
boolean | 开关 | disabled?: boolean |
'a' | 'b' | 枚举值 | size: 'sm' | 'md' | 'lg' |
() => void | 无参回调 | onClick: () => void |
(value: T) => void | 带参回调 | onChange: (value: string) => void |
React.ReactNode | 可渲染内容 | children: React.ReactNode |
React.CSSProperties | 内联样式 | style?: React.CSSProperties |
React.ComponentProps<'button'> | 继承原生属性 | 继承 button 所有属性 |
继承原生元素属性
当你的组件是对原生元素的包装时:
tsx
// 继承 button 的所有原生属性
interface ButtonProps extends React.ComponentProps<'button'> {
variant?: 'primary' | 'secondary'
}
function Button({ variant = 'primary', children, ...rest }: ButtonProps) {
return (
<button className={`btn-${variant}`} {...rest}>
{children}
</button>
)
}
// 现在可以使用所有原生 button 属性
<Button variant="primary" type="submit" disabled>
提交
</Button>泛型 Props
处理通用组件时使用泛型:
tsx
interface ListProps<T> {
items: T[]
renderItem: (item: T) => React.ReactNode
}
function List<T>({ items, renderItem }: ListProps<T>) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item)}</li>
))}
</ul>
)
}
// 使用时自动推断类型
<List
items={[{ id: 1, name: '张三' }]}
renderItem={(user) => <span>{user.name}</span>} // user 自动推断为 { id: number, name: string }
/>AI 协作指南
核心意图:让 AI 帮你设计类型安全的组件接口。
需求定义公式:
- 功能描述:组件需要接收 [数据列表]
- 交互方式:用户可以 [触发事件]
- 预期效果:组件根据 props 展示 [不同状态]
关键术语:interface、children、React.ReactNode、extends ComponentProps、泛型
交互策略:
- 先让 AI 列出组件需要的所有 props
- 让它定义类型接口
- 区分必填和可选
- 添加合理的默认值
避坑指南
- Props 是只读的:永远不要直接修改 props,需要改变时用 state
- 避免过度设计:不要预设太多"以后可能用到"的 props
- 回调命名规范:事件回调以
on开头,如onClick、onChange - 可选 props 记得设默认值:避免 undefined 导致的问题
验收清单
- [ ] Props 接口定义完整,类型准确
- [ ] 可选 props 有合理的默认值
- [ ] 使用
children实现内容插槽 - [ ] 复杂组件使用泛型保持类型安全
