为 React 函数组件添加泛型类型
在 React 项目中使用 TypeScript 开发时,我们经常会遇到需要让组件支持多种数据类型的场景。比如一个通用的列表组件,既可能渲染字符串数组,也可能渲染数字数组,或者自定义对象数组。这时候为函数组件添加泛型类型,就能让组件的类型定义更灵活,同时保证类型安全。
为什么需要泛型函数组件
如果不使用泛型,我们可能会写出如下的组件定义:
// 非泛型版本,只能接收 string 类型的列表项
interface StringListProps {
list: string[];
onItemClick: (item: string) => void;
}
function StringList(props: StringListProps) {
return (
<ul>
{props.list.map((item, index) => (
<li key={index} onClick={() => props.onItemClick(item)}>
{item}
</li>
))}
</ul>
);
}上面的组件只能处理字符串数组,如果我们需要渲染数字数组,就必须再定义一个NumberList组件,显然会造成大量重复代码。泛型组件可以解决这个问题,让同一个组件适配多种数据类型。
基础泛型函数组件写法
要给 React 函数组件添加泛型,最常见的方式是在函数定义时声明泛型参数,然后将泛型参数应用到 props 的类型定义中。示例如下:
// 泛型函数组件,T 是泛型参数,代表列表项的数据类型
interface GenericListProps<T> {
list: T[];
onItemClick: (item: T) => void;
// 可选的渲染函数,用于自定义列表项的展示逻辑
renderItem?: (item: T) => React.ReactNode;
}
function GenericList<T>(props: GenericListProps<T>) {
const { list, onItemClick, renderItem } = props;
return (
<ul>
{list.map((item, index) => (
<li key={index} onClick={() => onItemClick(item)}>
{renderItem ? renderItem(item) : String(item)}
</li>
))}
</ul>
);
}上面的代码中,我们定义了泛型参数T,GenericListProps<T>的list属性是T[]类型,点击回调的参数也是T类型。这样组件就可以适配任意类型的列表数据了。
使用泛型函数组件
在使用上面的泛型组件时,TypeScript 通常可以自动推断泛型类型,不需要手动指定。如果有特殊场景需要手动指定泛型类型,可以通过组件调用的方式显式传入泛型参数。
// 使用字符串数组的场景,TypeScript 会自动推断 T 为 string
function App() {
const handleStringClick = (item: string) => {
console.log('点击了字符串项:', item);
};
const handleNumberClick = (item: number) => {
console.log('点击了数字项:', item);
};
const handleUserClick = (item: { id: number; name: string }) => {
console.log('点击了用户项:', item.name);
};
return (
<div>
{/* 渲染字符串列表 */}
<GenericList
list={['苹果', '香蕉', '橙子']}
onItemClick={handleStringClick}
/>
{/* 渲染数字列表 */}
<GenericList
list={[1, 2, 3, 4]}
onItemClick={handleNumberClick}
/>
{/* 渲染自定义对象列表,使用 renderItem 自定义展示 */}
<GenericList
list={[
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
]}
onItemClick={handleUserClick}
renderItem={(user) => `用户ID: ${user.id}, 姓名: ${user.name}`}
/>
{/* 如果需要手动指定泛型类型(比如避免推断错误) */}
<GenericList<number>
list={[10, 20, 30]}
onItemClick={(num) => console.log(num * 2)}
/>
</div>
);
}可以看到,同一个GenericList组件可以处理字符串、数字、自定义对象三种不同类型的列表,而且每个场景下都有完整的类型提示,不会出现类型错误。
带默认类型的泛型组件
有时候我们希望泛型参数有一个默认类型,当使用方没有指定泛型类型时,自动使用默认类型。可以给泛型参数添加默认值:
// 泛型参数 T 默认是 string 类型
interface GenericListProps<T = string> {
list: T[];
onItemClick: (item: T) => void;
renderItem?: (item: T) => React.ReactNode;
}
// 组件定义时也需要带上默认泛型
function GenericList<T = string>(props: GenericListProps<T>) {
const { list, onItemClick, renderItem } = props;
return (
<ul>
{list.map((item, index) => (
<li key={index} onClick={() => onItemClick(item)}>
{renderItem ? renderItem(item) : String(item)}
</li>
))}
</ul>
);
}
// 使用时如果不指定泛型,默认 T 为 string
function DefaultGenericApp() {
return (
<GenericList
list={['默认字符串1', '默认字符串2']}
onItemClick={(item) => console.log('默认类型点击:', item)}
/>
);
}注意事项
- 泛型参数名建议使用单个大写字母,比如
T、U、K等,符合 TypeScript 的通用命名习惯,可读性更好。 - 如果组件有多个泛型参数,可以用逗号分隔,比如
<T, K>,分别对应不同的数据类型。 - 不要为了使用泛型而滥用泛型,只有当组件需要适配多种不确定类型的数据时,才适合添加泛型,否则会让类型定义变得复杂,反而降低可维护性。
- 如果组件需要导出给其他模块使用,要确保泛型的定义清晰,必要时可以添加注释说明每个泛型参数的作用。
React函数组件TypeScript泛型泛型组件组件类型安全前端开发 本作品最后修改时间:2026-05-22 16:34:07