React + TypeScript 实现泛型组件

2023-05-16

泛型类型

TypeScript 中,类型(interface, type)是可以声明成泛型的,这很常见。


interface Props<T> {
  content: T;
}  

这表明 Props 接口定义了这么一种类型:

  • 它是包含一个 content 字段的对象
  • content 字段的类型由使用时的泛型 T 决定

type StringProps = Props<string>;

let props: StringProps;

props = {
  // ? Type 'number' is not assignable to type 'string'.ts(2322)
  content: 42
};

props = {
  //
  content: "hello"
};  

或者,TypeScript 能够跟使用时候提供的值自动推断出类型 T,无需显式指定:


interface Props<T> {
  content: T;
}

function Foo<T>(props: Props<T>) {
  console.log(props);
}

/** 此时 Foo 的完整签名为: function Foo<number>(props: Props<number>): void */
Foo({ content: 42 });

/** 此时 Foo 的完整签名为: function Foo<string>(props: Props<string>): void */
Foo({ content: "hello" });  

上面因为 Foo 函数接收 Props<T> 作为入参,意味着我们在调用 Foo 的时候需要传递类型 T 以确定 Props<T>,所以 Foo 函数也变成了泛型。

当调用 Foo({ content: 42 }) 的时候,TypeScript 自动解析出 Tnumber,此时对应的函数签名为:


function Foo<number>(props: Props<number>): void;  

而我们并没有显式地指定其中的类型 T,像这样 Foo<number>({ content: 42 });

泛型组件

将上面的 Foo 函数返回 JSX 元素,就成了一个 React 组件。因为它是泛型函数,它所形成的组件也就成了 泛型组件/Generic Components


function Foo<T>(props: Props<T>) {
  return <div> {props.content}</div>;
}

const App = () => {
  return (
    <div className="App">
      <Foo content={42}></Foo>
      <Foo<string> content={"hello"}></Foo>
    </div>
  );
};  

一如上面的讨论,因为 TypeScript 可根据传入的实际值解析泛型类型,所以 <Foo<string> content={"hello"}></Foo>string 是可选的,这里只为展示,让你看到其实 React 组件还可以这么玩。

为了进一步理解泛型组件,再看下非泛型情况下上面的组件是长怎样的。


interface Props {
  content: string;
}

function Foo(props: Props) {
  return <div>{props.content}</div>;
}

const App = () => {
  return (
    <div className="App">
      {/* ? Type 'number' is not assignable to type 'string'.ts(2322) */}
      <Foo content={42}></Foo>
      <Foo content={"hello"}></Foo>
    </div>
  );
};  

以上,便是一个 React 组件常规的写法。它定义的入参 Props 只接收 string 类型。由此也看出泛型的优势,即大部分代码可复用的情况下,将参数变成泛型后,不同类型的入参可复用同一组件,不用为新类型新写一个组件。

除了函数组件,对于类类型的组件来说,也是一样可泛型化的。


interface Props<T> {
  content: T;
}

class Bar<T> extends React.Component<Props<T>> {
  render() {
    return <div>{this.props.content}</div>;
  }
}

const App = () => {
  return (
    <div className="App">
      <Bar content={42}></Bar>
      <Bar<string> content={"hello"}></Bar>
    </div>
  );
};  

一个更加真实的示例

一个更加实用的示例是列表组件。列表中的分页加载,滚动刷新逻辑等,对于所有列表数据都是通用的,将这个列表组件书写成泛型便可和任意类型列表数据结合,而无须通过其他方式来达到复用的目的,将列表元素声明成 anyRecord<string,any> 等类型。

先看不使用泛型情况下,如何实现这么一个列表组件。此处只看列表元素的展示以阐述泛型的作用,其他逻辑比如数据加载等先忽略。

列表组件 List.tsx


interface Item {
  [prop: string]: any;
}

interface Props {
  list: Item[];
  children: (item: Item, index: number) => React.ReactNode;
}

function List({ list, children }: Props) {
  // 列表中其他逻辑...
  return <div>{list.map(children)}</div>;
}  

上面,为了尽可能满足大部分数据类型,将列表的元素类型定义成了 [prop: string]: any; 的形式,其实和 Record<string,any> 没差。在这里已经可以看到类型的丢失了,因为出现了 any,而我们使用 TypeScript 的首要准则是尽量避免 any

然后是使用上面所定义的列表组件:


interface User {
  id: number;
  name: string;
}
const data: User[] = [
  {
    id: 1,
    name: "wayou"
  },
  {
    id: 1,
    name: "niuwayong"
  }
];

const App = () => {
  return (
    <div className="App">
      <List list={data}>
        {item => {
          // ? 此处 `item.name` 类型为 `any`
          return <div key={item.name}>{item.name}</div>;
        }}
      </List>
    </div>
  );
};  

这里使用时,item.name 的类型已经成了 any。对于简单数据来说,还可以接收这样类型的丢失,但对于复杂类型,类型的丢失就完全享受不到 TypeScript 所带来的类型便利了。

上面的实现还有个问题是它规定了列表元素必需是对象,理所应当地就不能处理元始类型数组了,比如无法渲染 ['wayou','niuwayong'] 这样的输入。

下面使用泛型改造上面的列表组件,让它支持外部传入类型。


interface Props<T> {
  list: T[];
  children: (item: T, index: number) => React.ReactNode;
}

function List<T>({ list, children }: Props<T>) {
  // 列表中其他逻辑...
  return <div>{list.map(children)}</div>;
}  

改造后,列表元素的类型完全由使用的地方决定,作为列表组件,内部它无须关心,同时对于外部传递的 children 回调中 item 入参,类型也没有丢失。

使用改造后的泛型列表:


interface User {
  id: number;
  name: string;
}
const data: User[] = [
  {
    id: 1,
    name: "wayou"
  },
  {
    id: 1,
    name: "niuwayong"
  }
];

const App = () => {
  return (
    <div className="App">
      <List list={data}>
        {item => {
          // ? 此处 `item` 类型为 `User`
          return <div key={item.name}>{item.name}</div>;
        }}
      </List>
      <List list={["wayou", "niuwayong"]}>
        {item => {
          // ? 此处 `item` 类型为 `string`
          return <div key={item}>{item}</div>;
        }}
      </List>
    </div>
  );
};  

转载于:https://www.cnblogs.com/Wayou/p/react_typescript_generic_components.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React + TypeScript 实现泛型组件 的相关文章

  • 【C++实现python字符串函数库】一:分割函数:split、rsplit

    C 43 43 实现python字符串函数库 split 与rsplit 方法 前言 本系列文章将介绍python提供的字符串函数 xff0c 并尝试使用C 43 43 来实现这些函数 这些C 43 43 函数在这里做单独的分析 xff0c
  • python处理excel链接_Python处理Excel文件实例代码

    由于工作需要 需要检查是否一个查询的一部分内容是有效的 查询存储在Excel中 文本内容页面的标题 和页面的URL格式中的每个细胞的超链接 所以我本能地想到使用Python来读取Excel文件并执行文本分析 然后为每个链接时 执行一个Htt
  • 无所事事的周末

    按理说 xff0c 晚上睡得很早 xff0c 早上应该起得早 不幸的是 xff0c 酒精已经渗入身体 xff0c 身体多个部位都不舒服 早上起的是很迟的 xff0c 已经到了上午十点钟 xff0c 起来后并没有做什么事情 xff0c 和舍友
  • CocosCreator的节点显示和隐藏

    隐藏和显示有两种方式 xff1a 1 禁止节点node的运行 xff0c 方法是x node active 61 false 此时隐藏了节点 xff0c 且节点不再运行 恢复节点正常运行 xff0c x node active 61 tru
  • php获取mysql数据并导出为txt_php提交过来的数据生成为txt文件

    一共两个文件 xff0c 具体链接数据库的部分给直接去除了 xff0c 前台是提交的文字部分 xff0c 一行一个 xff0c 在提交后另一个程序文件进行处理 xff0c 然后按照提交的文件名生成相应的txt 文件 xff0c 并在txt
  • (?!)正则表达式的用法

    xff08 xff1f xff01 xff09 表示不匹配一段字符串中的指定字符串 xff0c 例如 xff1a flag 61 True 指匹配指定部位的布尔值 xff0c 可以写成 xff1a s 43 flag s 43 61 s 4
  • HTML5资源汇总(更新游戏引擎cocos2d-html5)

    我也是现学现用 xff0c 想了解的可以看看效果 xff0c 想知道实现的也有源码 http cocos2d html5 org Cocos2d HTML5 API和Cocos2d x一致 xff0c 同样的代码可以支持cocos2d x
  • Sumo 模型细节_VehicleSpeed

    在仿真中 xff0c 对车速的影响是多方面的 每一种影响都为车速设定了上限 在任何给定情况下的实际速度是所有影响的最小速度 maxSpeed lt vType gt attribute maxSpeed 可以被认为是发动机的最大速度或驾驶员
  • python的一些语法糖

    1 Python中if else语句的多种写法 a b c 61 1 2 3 1 常规 if a gt b c 61 a else c 61 b 2 表达式 c 61 a if a gt b else b 3 二维列表 c 61 b a a
  • Ubuntu下安装使用Xfce4

    安装 xff1a 代码 sudo apt get install xfce4 xfce4 taskbar plugin xfce4 taskbar plugin是我需要 xff0c 你可不用 xff0c 完整安装xfce4 的桌面环境 su
  • 彻底卸载Xubuntu Kubuntu

    卸载Xubuntu sudo apt remove activity log manager apg apport gtk apt offline aptdaemon aptdaemon data atril atril common bi
  • Wincap安装出现“error opening file for writing wpcap.dll”之解决办法

    Wincap安装出现 error opening file for writing wpcap dll 之解决办法 安装Wireshark时 xff0c 一直出现下面的错误 xff0c 选择忽略这个错误 xff0c Wireshark能正常
  • sqlserver调用webapi

    1 开启组件 xff08 2012以上版本支持 xff09 sp configure 39 show advanced options 39 1 GO RECONFIGURE GO sp configure 39 Ole Automatio
  • 贪吃蛇c语言代码 vc++6.0,贪吃蛇代码-C语言版-VC++6.0

    这是一个贪吃蛇代码 运行环境VC 43 43 6 0 该程序不需要graphics h头文件 这是一个贪吃蛇代码 xff0c 运行环境VC 43 43 6 0 亲测完美运行 该程序在dos系统下运行 xff0c 不需要graphics h头
  • indent expected

    缩进问题 检查代码缩进 转载于 https www cnblogs com gcixx p 11448437 html
  • kibana配置文件说明书

    端口号 server port 5601 kibana服务安装的地址 server host 34 192 168 122 21 34 当使用代理时 xff0c 这里可能对应的是加工后的kibana的URL server basePath
  • ORACLE 清理SYSAUX表空间

    在数据库检查中发现SYSAUX表空间占用过大 xff0c SYSAUX是ORACLE10G开始提供的功能 xff0c 用于数据库为SYSTEM表空间减负 用以下语句查出相应的表空间值 select a tablespace name tru
  • Ubuntu怎么切换为中文版

    Ubuntu怎么切换为中文版 1 打开Ubuntu 2 打开设置 系统设置 xff1b 3 进入Language Support xff1b 4 安装语言 xff1b 5 这时在语言菜单中可以看到安装好的汉语 xff1b 6 将安装好的语言
  • django rest framework自定义返回格式

    一 默认response view from rest framework generics import ListAPIView from serializer import IdcSerializer from models impor
  • Go used as value问题

    练习Go变参时遇到一个报错 xff1a used as value 代码如下 xff1a 错误代码 func myfunc arg int for n 61 range arg fmt Printf 34 And the number is

随机推荐

  • 核密度图(直方图的拟合曲线)

    核密度图可以看作是概率密度图 xff0c 其纵轴可以粗略看做是数据出现的次数 xff0c 与横轴围成的面积是一 法一 xff1a seaborn的kdeplot函数专门用于画核密度估计图 参考 xff1a https www jianshu
  • WinCE6.0bootloader的研究

    为了加载操作系统映像至内存 xff0c Bootloader 在 BSP 的开发中至关重要 1 BootLoader的架构 1 1 Bootloader 简介 Bootloader 是建立在操作系统内核运行之前的一小段程序 xff0c 通过
  • vs2017和vs2019专业版和企业版

    步骤 xff1a 打开vs2017 xff0c 依次点击 gt 帮助 gt 注册产品 专业版 xff1a Professional KBJFW NXHK6 W4WJM CRMQB G3CDH 企业版 xff1a Enterprise NJV
  • vue 创建监听,和销毁监听(addEventListener, removeEventListener)

    最近在做一个有关监听scroll的功能 发现我添加监听之后一直不起作用 mounted window addEventListener 34 scroll 34 this setHeadPosition this setHeadPositi
  • 开发板boa移植

    1 xff0e 下载Boa源码 下载地址 http www boa org 最新发行版本 xff1a 0 94 13 下载 boa 0 94 13 tar gz 解压 xff1a tar xzf boa 0 94 13 tar gz 2 安
  • matlab调用cuda,window下matlab调用cuda的开发流程

    这两天抽点时间研究matlab调用cuda程序的问题 xff0c 发现网上这方面的资料比较少 xff0c 而且nvidia提供的白皮书描述的不够详尽 xff0c 因此对于开发流程进行总结 xff0c 希望大家有用 总的来说 xff0c ma
  • Media Types

    Available Formats XML HTML Plain text Registries included below applicationaudioexampleimagemessagemodelmultiparttextvid
  • PX4里面怎么添加驱动程序

    添加驱动程序 例如 xff0c 要把 GT100 esc cpp添加到一个固件里面去 xff0c 那么 1 首先把h文件放到src drv目录下面 xff0c 2 然后新建一个文件夹 xff0c 在这个文件夹里面放入 cpp文件和cmake
  • LACP详解

    转载自 1条消息 lacp协议 住在我对门的博客 CSDN博客 lacp协议 一 LACP 简介 1 LACP 协议简介 基于IEEE802 3ad 标准的LACP xff08 Link Aggregation Control Protoc
  • 正则表达式 (?=) 正向先行断言

    最近在练习正则表达式 xff0c 遇到了一道很有意思的题 xff0c 题目如下 我的答案如下 61 A Z 61 d 61 a z 8 对于这个答案的理解得先从正向先行断言的语法开始说起 正向先行断言的语法格式如下 expression1
  • FBOSS: Building Switch Software at Scale

    BOSS 大规模环境下交换机软件构建 本文为SIGCOMM 2018 论文 xff0c 由Facebook提供 本文翻译了论文的关键内容 摘要 xff1a 在网络设备 xff08 例如交换机和路由器 xff09 上运行的传统软件 xff0c
  • 云技术入门指导:什么是云计算技术,云技术用什么语言开发

    云计算技术 xff1a 这里只是列出我所知道的 xff0c 希望大家对云计算技术有所了解 xff1a 一首先让大家明白什么是云端 xff0c 所谓云端需要两层理解 xff08 1 xff09 服务不在本地 xff0c 这一层可以理解为服务器
  • 重启虚拟机,虚拟机上服务无法访问,关闭防火墙。

    重启虚拟机 xff0c 虚拟机上服务无法访问 xff0c 关闭防火墙 systemctl stop firewalld service 转载于 https www cnblogs com yangcl blogs p 10552119 ht
  • 视频教程-基于X210的裸机时钟温度显示器-第1/3季视频课程-嵌入式

    基于X210的裸机时钟温度显示器 第1 3季视频课程 互联网课程品牌 朱老师物联网大讲堂 创始人 精通U Boot Linux kernel移植及驱动程序开发 精通C C 43 43 Java C 等语言 xff0c 熟悉ARM Corte
  • ubuntu设置开机默认进入界面及命令行下开启图像界面

    前言 环境 xff1a ubuntu12 04 一 ubuntu设置默认开机界面 在网上查看了好几种方法 xff0c 对于当前环境方便或者有用的方式是对 etc default grub文件进行设置 1 默认开机命令行界面 file etc
  • 详解摄像头各个引脚的作用关系

    智能手机摄像头原理图解教程 http wenku baidu com link url 61 KSK7Go57xYfrwtUjOoXU8D23D rUtKzjeMAxd0h Hrdf7G fu5V8o 7oXgP7TY4EFwkniKrcM
  • 如何借助 OVN 来提高 OVS 在云计算环境中的性能

    众所周知 xff0c OpenvSwitch 以其丰富的功能和不错的性能 xff0c 已经成为 Openstack 部署中最受欢迎的虚拟交换机 由于 Openstack Neutron 的架构引入了一些性能问题 xff0c 比如 neutr
  • 从域环境搭建到域渗透

    转发 xff1a 从域环境搭建到域渗 透 xff08 上 xff09 从域环境搭建到域渗 透 xff08 下 xff09 转载于 https www cnblogs com little kwy p 11622550 html
  • 域渗透基础之环境搭建(单域到组件域林)

    转发 xff1a https www e learn cn content qita 2484245 之前练习域渗透的环境被我弄丢了 重新搭建一个完整的域环境吧 域渗透的基础还是环境的搭建 xff0c 单域到域树再到域林 单域环境搭建 创建
  • React + TypeScript 实现泛型组件

    泛型类型 TypeScript 中 xff0c 类型 xff08 interface type xff09 是可以声明成泛型的 xff0c 这很常见 interface Props lt T gt content T 这表明 Props 接