React中常见的TypeScript定义使用

2023-11-10

前言

在我学习typescript时,想在react中使用typescript写代码,从头开始的时候是懵逼的,因为官方文档并没有使用typescript的教程,多是自己在网上查,自己看定义摸索

所以今天把我用过的,总结归纳一下,希望能帮助到同样在摸索的同学

以下代码react版本为16.13.1,在create-react-app官方typescript模版中无报错

类型简述

一些React的内置类型

  • React.ReactElement —— 使用React.createElement创建的,可以简单理解为React中的JSX的元素
  • React.ReactNode —— <div>xxx</div> xxx的合法类型
  • React.CSSProperties —— 组件内联的style对象的类型
  • React.RefObject —— React.createRef创建的类型,只读不可改
  • React.MutableRefObject —— useRef创建的类型,可以修改
  • ...

组件声明

组件声明分为类组件和函数组件

类组件

类组件使用的定义主要为React.Component<P,S>React.PureComponent<P,S,SS>

interface AppProps {
  value: string;
}
interface AppState {
  count: number;
}
class App extends React.Component<AppProps, AppState> {
  static defaultProps = {
    value: "",
  };
  state = {
    count: 0,
  };
}
复制代码

React.Component<P,S>这里的Pprops的类型,Sstate的类型,可以写为React.Component<AppProp>,因为state的类型会自己推断

在上面PureComponent中还有个SS,这个SSgetSnapshotBeforeUpdate的返回值

函数组件

函数组件定义的方式简单来看有两种,一种是使用React.FC,一种是直接给props写上定义

interface AppProps {
  value?: string;
}

const App: React.FC<AppProps> = ({ value = '', children }) => {
    // ...
};
复制代码

React.FC的意思是FunctionComponent,如果使用了React.FC,它在定义里就已经规定好了children的类型和函数的返回值,所以可以直接用children

如果是直接给props写上定义,就需要自己定义children的类型

interface AppProps {
  value?: string;
  children?: React.ReactNode; // 自己定义children的类型
}

function App({ value = "", children }: AppProps) {
  return <>{children}</>;
}
复制代码

使用function来定义而不是箭头函数的优点是可以使用泛型组件

Hooks声明

hooks的声明如果不知道如何用ts定义可以直接点进去看看

useState

useState可以使用泛型传参或者自动推断

const [state, setState] = useState(''); // state的类型为string,自动推断
const [state, setState] = useState<string>(); // state的类型为 string | undefined
// 给初值
const [state, setState] = useState<string | null>(null); // state的类型为 string | null
复制代码

useRef

useRef同样也会自动推断

const ref = useRef(""); // ref.current的类型为 string
// 泛型
type Value = { value: string };
const ref = useRef<Value>({ value: "" });
// ref为html元素
const ref = useRef<HTMLDivElement>(null);
return <div ref={ref} />;
复制代码

需要注意的是如果ref为元素,那么初始值得写个null才不会报错

useReducer

useReducer相对来说要写的更多一点,可以自动推断,所以不需要手动写泛型类型(其实我也不知道手动写怎么写Orz)

// state类型
interface ReducerState {
  value: string;
}
// action类型
interface AnyAction {
  type: string;
  [key: string]: any;
}
// reducer函数
const reducer: React.Reducer<ReducerState, AnyAction> = (state, action) => {
  switch (action.type) {
    default:
      return state;
  }
};
// 初始值
const initialState: ReducerState = { value: "" };

const [state, dispatch] = useReducer(reducer, initialState);
// state 的类型为 ReducerState
// dispatch 的类型为 React.Dispatch<AnyAction>
复制代码

Action也可以是多个不同的Action的联合类型

useImperativeHandle

useImperativeHandle这个钩子可以把内部方法通过ref暴露出去,用ts也是要写多一点,类型都需要标注清楚

所以需要使用到React.forwardRef,可以先看下一节

// props
interface AppProps {
  value: string;
}
// useImperativeHandle获取到ref的类型
interface Handle {
  get: () => string;
}

const App = React.forwardRef<Handle, AppProps>(({ value }, ref) => {
  // 定义
  useImperativeHandle(ref, () => ({
    get: () => `handle get value : ${value}`,
  }));
  return null;
});
// 使用
const handleRef = useRef<Handle>(null);
// handleRef.current?.get();
return <App value="hello" ref={handleRef} />;
复制代码

自定义hook需要注意的

有如下钩子

const useCustomHook = () => {
  const [state, setState] = useState("");
  const set = (value: string) => {
    if (!value) return;
    setState(value);
  };
  return [state, set];
};
// 使用
const [state, setState] = useCustomHook();
setState('hello') // This expression is not callabl
复制代码

自定钩子还需要定义返回值才行

- const useCustomHook = () => {
+ const useCustomHook = (): [string, (value: string) => void] => {
复制代码

React.forwardRef

React.forwardRef<T, P = {}>只需要传props的类型和ref的类型,第一个Tref的类型,Pprops的类型

const App = React.forwardRef<HTMLDivElement, AppProps>(({ value }, ref) => {
  return <div ref={ref} />;
});
// 使用
const ref = useRef<HTMLDivElement>(null);
return <App value="hello" ref={ref} />;
复制代码

React.ForwardRefRenderFunction

定义为该类型的函数可以放进React.forwardRef函数中作为参数

// 定义
const forwardRender: React.ForwardRefRenderFunction<
  HTMLDivElement,
  AppProps
> = ({ value }, ref) => {
  return <div ref={ref} />;
};
const App = React.forwardRef(forwardRender);
// 使用
const ref = useRef<HTMLDivElement>(null);
return <App value="hello" ref={ref} />;
复制代码

React.createContext

泛型有自动推断的功能,所以useContext就不需要再写上类型了

interface ContextType {
  getPrefixCls: (value: string) => string;
}

const context = React.createContext<ContextType>({
  getPrefixCls: (value) => `prefix-${value}`,
});

const App = () => {
  const { getPrefixCls } = useContext(context);
  getPrefixCls("App"); // prefix-App
  return null;
};
复制代码

React.cloneElement

如果使用的React.FC定义的组件,它的children类型默认是React.ReactNode,需要显式转为React.ReactElement

const App: React.FC = ({ children }) => {
  return React.cloneElement(children as React.ReactElement, { value: "hello" });
};
// 也可以覆写定义
const App: React.FC<{ children: React.ReactElement }> = ({ children }) => {
  return React.cloneElement(children, { value: "hello" });
};
复制代码

React.ComponentType

通过React.ComponentType<P>定义的组件可以将变量名传入组件,在组件内调用,高阶组件通常会使用

interface AppProps {
  value: string;
}
const App: React.FC<AppProps> = (props) => {
  return null;
};
// React.ComponentType定义组件
function HOC<T>(Component: React.ComponentType<T>) {
  return function (props: T) {
    return <Component {...props} />;
  };
}
const WrappedComponent = HOC(App);
// 调用
<WrappedComponent value="hello" />
复制代码

泛型参数的组件

泛型参数的组件是typescript2.9版本新增的,第一次看见是在ant-deisgn

一个很简单的例子就是Select组件

<Select<number>>
  <Select.Option value={1}>1</Select.Option>
  <Select.Option value={2}>2</Select.Option>
</Select>
复制代码

类组件的定义

// 定义泛型参数的组件
class GenericComponent<P> extends React.Component<P> {
  internalProp: P;
  constructor(props: P) {
    super(props);
    this.internalProp = props;
  }
  render() {
    return null;
  }
}

type Props = { a: number; b: string };

<GenericComponent<Props> a={10} b="hi" />; // OK
<GenericComponent<Props> a={10} b={20} />; // Error
复制代码

函数组件的定义

function GenericComponent<P>(props: P) {
  const internalProp = useRef(props)
  return null;
}
复制代码

函数组件写起来可简洁太多了…

事件处理

也是多种多样

const App = () => {
  // React.MouseEventHandler
  const onClick: React.MouseEventHandler<HTMLInputElement> = (e) => {
    console.log(e.currentTarget.value);
  };
  // React.ChangeEventHandler
  const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
    console.log(e.currentTarget.value);
  };
  // React.FocusEventHandler
  const onFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {
    console.log(e.currentTarget.value);
  };
  return <input onClick={onClick} onChange={onChange} onFocus={onFocus} />;
};
复制代码

如果有事件不清楚该如何定义类型,可以点组件上的事件名去看看定义

需要注意的是只有e.currentTarget才会有对应的元素类型,e.target是没有的,它的类型是EventTarget

总结

想不出还有啥了,想起来再补充

ts自带了一些工具泛型,比如OmitPick,在开发的时候还是有帮助,可以看看我以前的总结

最后,祝大家身体健康,工作顺利!


太惨了,tsx连代码高亮都没有,只能说还是prismjs好使,highlightjs不太行


作者:ZHANGYU
链接:https://juejin.im/post/5ed36b616fb9a047fa04f112
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

React中常见的TypeScript定义使用 的相关文章

  • Vite+Ts+pnpm自定义组件发布到私有npm仓库

    Vite Ts pnpm自定义组件发布到私有npm仓库 创建发布流程 新建vite相关项目 新建文件夹 并用打开当前终端输入pnpm init初始化仓库 新建pnpm workspace yaml文件 说明共用空间 packages all
  • 前端面试题精心整理(一)-TypeScript

    文章目录 TypeScript相关问题及知识点 Q1 ts中type和interface的区别 A1 有相同点与不同点 具体内容如下 Q2 ts中interface和class的区别 分别什么时候使用 A2 interface和class都
  • vite创建vue2项目

    使用vite首先需要注意官方给出的兼容性注意 Vite 需要 Node js 版本 14 18 16 然而 有些模板需要依赖更高的 Node 版本才能正常运行 当你的包管理器发出警告时 请注意升级你的 Node 版本 1 初始化vite项目
  • TypeScript的一些安装、转换、热更新等配置方法

    安装 首先得有node然后在文件目录中git bash 输入npm i g typescript 安装成功后输入tsc测试是否安装成功 ts转js 浏览器不认识ts需要将ts转换为js让浏览器进行编译 在当前目录下git bash输入 ts
  • 阿里云实践 - HTML5断点播放m3u8视频(videojs)

    场景 HTML5页面需要通过
  • Vue3描述列表(Descriptions)

    整体功能效果与 ant design vue 保持高度一致 包含两种组件 Descriptions 和 DescriptionsItem 必须搭配使用 效果如下图 在线预览 APIs Descriptions 参数 说明 类型 默认值 必传
  • React.Suspense和React.lazy代替react-loadable实现路由懒加载

    1 react loadable使用 import RouteConfig from react router config import Loadable from react loadable import React from rea
  • TypeScript中的联合类型、类型别名、接口、类型断言

    一 联合类型 在TypeScript中 联合类型 Union Types 是指用 符号将多个类型组合成一个的类型 这种类型可以包含不同的类型 例如字符串 数字或对象 这些不同类型的值可以赋值给联合类型的变量 而在使用这个变量时 需要对不同类
  • vue2.x+ts项目,在props type导入自定义接口类型报‘xxx‘ only refers to a type, but is being used as a value here处理办法

    一 报错 xxx only refers to a type but is being used as a value here 在Props中使用自定义类型约束时 报上面的错误 然后 我在网上查找教程 找到一个说在ts中导出class 接
  • 【TS】Error: Property ‘children‘ does not exist on type ‘X‘

    最近 在做项目模块的迁移 新项目需要使用ts 遇到的问题有点多 记录一下 先来复现一下场景 import React from react type PersonProps name string age number const Pers
  • TypeScript中的模块与命名空间

    一 模块 在TypeScript中 模块是一种组织和封装代码的方式 模块使得代码可以按照特定的规则划分为不同的文件 并且可以在这些文件之间进行导入和导出 从而实现代码的重用和组织 1 默认导入导出 默认模块导出是一种特殊的导出语法 在一个模
  • TypeScript中的泛型(泛型函数、接口、类、泛型约束)

    一 泛型函数 TypeScript泛型是一种可以使代码具有更高的可重用性和泛化能力的特性 通过泛型 我们可以定义一种通用的类型或函数 使其能够应对多种类型的输入 泛型在类 函数 接口等多种场景下都可以使用 具体来说 在定义泛型函数时 我们可
  • React 好用的工具库

    俗话说的好 工欲善其事 必先利其器 笔者在开发 React 项目的时候 总结出一些很不错的 React 库 可以提高开发效率 满足业务需求 接下来将一一介绍它们 UI组件库 Ant Design 要说 React 最受欢迎的 UI 组件库
  • useMemo与useCallback使用指南

    在介绍一下这两个hooks的作用之前 我们先来回顾一下react中的性能优化 在hooks诞生之前 如果组件包含内部state 我们都是基于class的形式来创建组件 当时我们也知道 react中 性能的优化点在于 调用setState 就
  • react hooks 和 react-redux hooks 应用场景

    目前 Hooks 应该是 React 中最火的概念了 在阅读这篇文章之前 希望你已经了解了基本的 Hooks 是什么 下面就介绍一下简单的使用场景 react hooks useState useState是react自带的一个hook函数
  • TypeScript类型注解和类型推断

    类型注解和类型推断 类型注解 let count number count 123 这段代码就是类型注解 意思是显示的告诉代码 我们的count变量就是一个数字类型 这就叫做类型注解 当你明白了类型注解的概念之后 再学类型推断就更简单了 先
  • TS复习----TS中的接口

    目录 概念 属性接口 函数类型接口 可索引的类型 类类型接口 接口继承 概念 接口的作用 在面向对象编程中 接口是一种规范的定义 他定义了行为和动作的规范 在程序设计里面 接口起到了一种限制和规范的作用接口定义了某一批类所需要遵守的规范 接
  • React 条件渲染最佳实践(7 种方法)

    在 React 中 条件渲染可以通过多种方式 不同的使用方式场景取决于不同的上下文 在本文中 我们将讨论所有可用于为 React 中的条件渲染编写更好的代码的方法 条件渲染在每种编程语言 包括 javascript 中都是的常见功能 在 j
  • 前端多级搜索条件,不走后台

    handleSearch 备份数据 let arr JSON parse JSON stringify this tableData form是查询条件 通过遍历key值来循环处理 Object keys this form forEach
  • 编写一套工具库并上传NPM

    你的 工具箱 开箱即可用的 directive utils 说明 vue3 directive tools 是一个方便在 Vue 3 Ts 项目中快速使用的 directive tool 的 npm 插件 它允许您轻松地在项目中添加多种功能

随机推荐

  • TCP协议疑难杂症全景解析

    原文地址 http blog csdn net dog250 article details 6612496 说明 1 本文以TCP的发展历程解析容易引起混淆 误会的方方面面 2 本文不会贴大量的源码 大多数是以文字形式描述 我相信文字看起
  • multiset和set,map和multimap的区别

    一 set和multiset的差异和相同 set是一个集合容器 其中所包含的元素是唯一的 集合中的元素按一定的顺序排列 元素插入过程是按排序规则插入 所以不能指定插入位置 set采用红黑树变体的数据结构实现 红黑树属于平衡二叉树 在插入操作
  • 查看GPU使用的最佳方式

    1 watch n 1 nvidia smi 最有名 没有之一 nvidia自带了一个nvidia smi的命令行工具 会显示GPU使用情况 作为监控 GPU 的工具就显得有点过于简陋了 比如 Process name 栏只显示命令行的程序
  • Redis布隆过滤器详解

    目录 一 前言 二 RedisBloom 安装与使用 三 RedisBloom 常用命令汇总 四 通过 Jedis 使用 RedisBloom 五 Redisson 封装的布隆过滤器 六 使用哪种方式的过滤器比较好 一 前言 布隆过滤器 B
  • 【数据结构与算法】时间复杂度与空间复杂度

    目录 一 前言 二 时间复杂度 1 概念 二 大O的渐进表示法 概念 总结 三 常见时间复杂度计算举例 例1 例2 例3 例4 例5 计算冒泡排序的时间复杂度 例6 二分算法的时间复杂度 例7 阶乘递归Fac的时间复杂度 例8 斐波那契递归
  • js异步提交form表单之serialize()方法及FormData对象

    serialize 和FormData对象都可将表单数据序列化 后通过ajax异步提交 但二者有实质区别 1 serialize serialize 是JQuery方法 可序列化表单值创建 URL 编码文本字符串 就是将表单数据以字符串的形
  • 浏览器的工作原理

    浏览器可以被认为是使用最广泛的软件 本文将介绍浏览器的工 作原理 我们将看到 从你在地址栏输入google com到你看到google主页过程中都发生了什么 将讨论的浏览器 今天 有五种主流浏览器 IE Firefox Safari Chr
  • java.lang.UnsatisfiedLinkError: No implementation found for

    E AndroidRuntime FATAL EXCEPTION main Process com example pimr PID 20314 java lang UnsatisfiedLinkError No implementatio
  • leecode刷题笔记-数组

    数组题注意事项 1 切记while循环的循环条件一定要判断遍历长度是否越界且要先判断该条件 否则就会报错 例如 while j
  • 50道编程小题目之【分解质因数】

    题目 将一个正整数分解质因数 例如 输入90 打印出90 233 5 python解题代码 ii int input 请输入一个正整数 jj 2 ii b ii fj while jj lt ii if ii jj 0 if ii jj f
  • linux下安装helm

    我这里使用的系统是centos7 6 Helm是一个kubernetes应用的包管理工具 用来管理charts 预先配置好的安装包资源 有点类似于Ubuntu的 apt 和CentOS中的 yum 方式一 使用官方提供的脚本一键安装 点击查
  • wallhaven.cc网站图片超清壁纸爬虫

    测试时间 2021 02 16 1 参考博客 2 python代码 1 参考博客 From 侵删 https blog csdn net qq 41849471 article details 89607706 2 python代码 图片保
  • python search用法,Python-re中search()函数的用法详解(查找ip)

    1 首先来看一下search 和find 的区别 import re s1 2221155 search 字符串第一次出现的位置 print re search 1 s1 print s1 find 1 它们的输出分别是 search 函数
  • 苹果系统itunes连iphone连不上服务器,itunes不识别iphone,iPhone连接不上iTunes怎么解决?连接不上iTunes怎么办?...

    今天一网友求助 itunes不识别iphone iPhone手机插上电脑后可以弹出设备 在电脑里面可以显示并能打开手机的相册 怎么样iphone也连不上iTunes 而换另外的一个iPhone连接又很正常 iPhone连接不上iTunes怎
  • 6-17 使用函数实现字符串部分复制 (20 分)

    6 17 使用函数实现字符串部分复制 20 分 本题要求编写函数 将输入字符串t中从第m个字符开始的全部字符复制到字符串s中 函数接口定义 void strmcpy char t int m char s 裁判测试程序样例 include
  • 使用JSONP解决跨域

    1 首先需要知道什么是跨域 浏览器从一个域名的网页去请求另一个域名的资源时 域名 端口 协议任一不同 都是跨域 出于浏览器的同源策略限制 同源策略 Sameoriginpolicy 是一种约定 它是浏览器最核心也最基本的安全功能 如果缺少了
  • c语言中auto、register、extern、static用法

    转载地址 http www 111cn net net c 38998 htm 四种存储类别说明符有两种存储期 自动存储期和静态存储期 auto和register对应自动存储期 具有自动存储期的变量在进入声明该变量的程序块是被建立 它在该程
  • 删除system/app下的apk

    要删除系统system app目录下的的APK 由于 system app目录默认是只读 所以 想要删除这些APK 必须首先获得system目录的删除权限 通过如下步骤删除system app下的apk文件 1 连接设备 如果是手机则需要打
  • Linux 基础笔记 权限与文件管理

    Linux 基础笔记 权限与文件管理 字符界面中退出登录可用哪种方法 exit 命令或 Ctrl D 组合键 pwd命令的功能是什么 显示当前目录的绝对路径 当前目录为 home 使用以下哪个命令后可进入 home Studd test目录
  • React中常见的TypeScript定义使用

    前言 在我学习typescript时 想在react中使用typescript写代码 从头开始的时候是懵逼的 因为官方文档并没有使用typescript的教程 多是自己在网上查 自己看定义摸索 所以今天把我用过的 总结归纳一下 希望能帮助到