TS与React的完美融合:泛型组件
您好,我是沧沧凉凉,是一名前端开发者,目前在掘金、知乎以及个人博客上同步发表一些学习前端时遇到的趣事和知识,欢迎关注。
由于JSX的存在,React解锁了JavaScript的完全编程能力,所以它对TypeScript也有着完美的支持,其中泛型组件是React项目使用了TypeScript后才获得一项新技能。
在之前的很多文章中,我都提到TypeScript用来写中大型项目拥有非常多的优势,无论是代码提示还是类型校验,都能大大的降低你项目中的隐藏BUG,毫不夸张的说,正确使用TypeScript比使用JavaScript的隐藏BUG少百分之80左右。
那么在讲解泛型组件之前,我们先交代一下TypeScript中的泛型到底是什么:
1. 泛型
先看一下下面这个简单的函数。
function myPrint(p: number) {
console.log(p);
return p;
}
myPrint
这个函数,参数p
被限制为一个数字类型,这个时候如果你想要传入一个字符串类型,那么TypeScript就会进行报错。
但是你就是想要这个函数的参数p
不仅能是数字类型,还能是字符串类型,那该怎么办?
可以像下面这样使用联合类型,表示参数p
可以是数字类型也可能是字符串类型。
function myPrint(p: number | string) {
console.log(p);
return p;
}
但如果这个时候参数p
也可以是数组或者对象或者任意的类型呢?那么这个时候我们的any!(划掉)泛型就出场了!
先说一点,将参数p
定义为any
也是可以解决这个需求的,但是我想说的是!在任何情况下,都尽量不要使用any!因为它会失去类型校验。
我们先来看一下上面的三种函数的返回值有什么不同。
可以看到当参数p
声明为any
时,该函数的返回值也是any
,你可能觉得没什么,因为你自己写的代码你知道这个返回值到底是什么类型,但是如果代码量一多或者别人接手你的代码,又或者过了好多个月后,你还知道res
这个值是什么类型嘛?
上面的代码中无论是联合类型还是any
都没有完美的解决这个问题,我想要的结果是传入number
返回值就是number
,传入string
返回值就是string
,也就是说我想要的是传入什么类型,返回值就是什么类型。
这个时候就需要用到泛型了。
function myPrint<T>(p: T) {
console.log(p);
return p;
}
泛型声明很简单,就是在函数名后面加一个<>
至于尖括号中的内容,你写什么都可以,但是我们默认约定是T
,如果是多个的话那么就是<T,U>
。
这个时候我们再看一下该函数的返回值。
可以看到,使用泛型后,你传入的是什么类型,那么它返回的就是什么类型,这就是泛型的好处。
2. 泛型组件
那么说了这么多,React的泛型组件又是什么呢?我们先来看一段代码:
// 定义Test的Props
interface TestProps {
data: string;
// 这里是重点
onFinish: (value: string) => void;
}
function Test({ data, onFinish }: TestProps) {
return (
<>
<button
onClick={() => {
onFinish(data);
}}
>
数据
</button>
</>
);
}
export default function App() {
return (
<div className="App">
<Test
data="这是数据"
// 注意这里的value的类型
onFinish={(value) => {
console.log(value);
}}
/>
</div>
);
}
看了上面的代码,不知道你们是否有一种恍然大悟(一脸懵逼)的感觉,这段代码我想表达的意思是,在父组件中使用onFinish
想要获取子组件中data
的值。
可以看到onFinish
中的value
是个string类型。
但是我们想让onFinish
中value
参数的类型和Test
的data
参数类型保持一致,即data="这是数据"
是一个string
类型那么onFinish
中的value
也为string
,data
为number
那么value
也为number
,换句话说data
是什么类型,那么value
就应该是什么类型。
至于怎么做,直接看代码:
// 定义Test的Props
interface TestProps<T> {
data: T;
// 这里是重点
onFinish: (value: T) => void;
}
function Test<T>({ data, onFinish }: TestProps<T>) {
return (
<>
<button
onClick={() => {
onFinish(data);
}}
>
数据
</button>
</>
);
}
export default function App() {
return (
<div className="App">
<Test
data="这是数据"
// 注意这里的data的类型
onFinish={(value) => {
console.log(value);
}}
/>
</div>
);
}
将上面的代码进行稍微的调整,加入前面我们讲的泛型,这个时候我们看一下value
是什么类型。
可以看到,data
的类型是string
,那么value
也为string
,我们将data
改成number
试一下:
可以看到value
也变成了number
,那么我们将data
改成数组类型呢?
依然能够正确的显示类型,到这里你应该初步了解了React中的泛型组件了吧?
3. 最后
React的泛型组件一般都是用来封装一个通用的组件,比如在Antd UI中,表格组件就用到了泛型声明,在Antd中还有非常多的组件用到了泛型,如果你想要二次封装这些组件,那么你就需要了解泛型。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!