由微软推出的TypeScript自从一推出就广受关注,现在无论开发前端React/Vue,还是后端API,很多项目中都广泛接受了TypeScript。下面介绍如何在React中通过TypeScript来使用泛型。

基本组件
先来看一个最基本的List组件:
ListComponent.tsx
type ListProps = {
data: string[];
clickHandler: (value: string) => void;
};
export const ListComponent = ({ data, clickHandler }: ListProps) => {
return (
<div>
<h2>Generic list component</h2>
{data.map((item, index) => {
return (
<li key={index} onClick={() => clickHandler(item)}>
{item}
</li>
);
})}
</div>
);
};
调用部分
function App() {
const students = ['Lucy', 'Paula', 'Jim', 'Andy'];
const handleClick = (item: string) => {
console.log(item);
}
return (
<div className="App">
<ListComponent data={students} clickHandler={handleClick}/>
</div>
);
}
使用泛型
在上面例子中,ListComponent只能处理字符型的数据。如果传递过来的是数字,或者对象类型,TS就会报错。这个时候,可以通过联合类型来解决这个问题:
type ListProps = {
data: string[] | number[];
clickHandler: (value: string | number) => void;
};
但这种方式的通用性仍然很差,尤其是在处理对象数组的时候。那么,就可以使用泛型来达到这个要求:
type ListProps<T> = {
data: T[];
clickHandler: (value: T) => void;
};
export const ListComponent = <T extends {name: string}>({
data,
clickHandler,
}: ListProps<T>) => {
return (
<div>
<h2>Generic list component</h2>
{data.map((item, index) => {
return (
<li key={index} onClick={() => clickHandler(item)}>
{item.name}
</li>
);
})}
</div>
);
};
需要注意的是,这里对T的类型进行了限定,它继承自任何包含’name’属性的对象。因此,在使用这个组件的时候,就要确保传入的数组中每个对象都包含’name’属性:
function App() {
const students = [
{ name: "Lucy", age: 20 },
{ name: "Paula", age: 21 },
{ name: "Jim", age: 18 },
{ name: "Andy", age: 22 },
];
const handleClick = (item: {name: string}) => {
console.log(item);
};
return (
<div className="App">
<ListComponent data={students} clickHandler={handleClick} />
</div>
);
}
注意事项
可以使用以下方式来限定这个组件能够使用的类型,比如:
export const MyComponent = <T extends string | number>(
data,
processing,
) = {
// ...
}
如果想要允许任何对象类型的话,可以这样:
export const MyComponent = <T extends {}>(
或者只允许某种特定的对象类型(对象中至少包含指定的属性,比如name,age,address,也可以包含更多的属性):
export const MyComponent = <T extends {name:string, age:number}>(