序言

本文会侧重于TypeScript(以下简称TS)在项目中与React的结合使用情况,而非TS的基本概念。关于TS的类型查看可以使用在线TS工具TypeScript游乐场

React元素相关

React元素相关的类型主要包括ReactNodeReactElementJSX.Element

  • ReactNode。表示任意类型的React节点,这是个联合类型,包含情况众多;
  • ReactElement/JSX。从使用表现上来看,可以认为这两者是一致的,属于ReactNode的子集,表示“原生的DOM组件”或“自定义组件的执行结果”。

使用示例如下:

// ReactNode
const a: React.ReactNode =
  null ||
  undefined || <div>hello</div> || <MyComp title="world" /> ||
  "abc" ||
  123 ||
  true;

// ReactElement和JSX.Element
const b: React.ReactElement = <div>hello world</div> || <MyComp title="good" />;

const c: JSX.Element = <div>hello world</div> || <MyComp title="good" />;

原生DOM相关

原生的 DOM 相关的类型,主要有以下这么几个:ElementHTMLElementHTMLxxxElment

简单来说: Element = HTMLElement + SVGElement

SVGElement一般开发比较少用到,而HTMLElement却非常常见,它的子类型包括HTMLDivElementHTMLInputElementHTMLSpanElement等等。

因此我们可以得知,其关系为:Element > HTMLElement > HTMLxxxElement,原则上是尽量写详细。

React合成事件相关

在 React 中,原生事件被处理成了React 事件,其内部是通过事件委托来优化内存,减少DOM事件绑定的。言归正传,React 事件的通用格式为[xxx]Event,常见的有MouseEventChangEventTouchEvent,是一个泛型类型,泛型变量为触发该事件的 DOM 元素类型。

示例如下:

// input输入框输入文字
const handleInputChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
  console.log(evt);
};

// button按钮点击
const handleButtonClick = (evt: React.MouseEvent<HTMLButtonElement>) => {
  console.log(evt);
};

// 移动端触摸div
const handleDivTouch = (evt: React.TouchEvent<HTMLDivElement>) => {
  console.log(evt);
};

与hooks的结合

在hooks中,并非全部钩子都与TS有强关联,比如useEffect就不依赖TS做类型定义,我们挑选比较常见的几个和TS强关联的钩子来看看。

useState

  1. 如果初始值能说明类型,就不用给 useState 指明泛型变量;
// 这样写是不必要的,因为初始值0已经能说明count类型
const [count, setCount] = useState<number>(0);

// 这样写好点
const [count, setCount] = useState(0);
  1. 如果初始值是 nullundefined,那就要通过泛型手动传入你期望的类型,并在访问属性的时候通过可选链来规避语法错误。
interface IUser {
  name: string;
  age: number;
}

const [user, setUser] = React.useState<IUser | null>(null);

console.log(user?.name);

useRef

这个 hook 比较特别,它通常有两种用途:

  1. 用来连接 DOM,以获取到 DOM 元素;
// 连接DOM,初始值赋值为null,不能是undefined,如要指明泛型变量需要具体到HTMLxxxElement
// 如果我们确定inputRef.current在调用时一定是有值的,可以使用非空断言,在null后添加!
const inputRef = useRef<HTMLInputElement>(null!);

const handleClick = () => {
  inputRef.current.focus(); // 当然不用非空断言,用inputEl.current?.focus()可选链也是可以的
}

return (
  <input ref={inputRef} />
  <button onClick={handleClick}>点击</button>
)
  1. 用来存储变量,由于是存储在函数式组件的外部,比起 useState,它不会存在异步更新的问题,也不会存在由capture-value特性引发的过时变量的问题,但是要注意赋值后由于ref引用没变,不会引起重渲染。
// 通过初始值来自动指明泛型变量类型
const sum = useRef(0);

// 通过.current直接赋值
sum.current = 3;
// 不存在异步更新问题
console.log(sum.current); // 3

useSelector

useSelector用于获取store中的状态,其第一个固定参数为函数,函数的入参即为store,而store的类型RootState需要在store中提前定义好,一种常见的定义如下:

在store.ts中:

const store = createStore(rootReducer);

export type RootState = ReturnType<typeof rootReducer>;

使用时:

const { var1, var2 } = useSelector((store: RootState) => store.xxx);

自定义 hook

如果我们需要仿照 useState 的形式,返回一个数组出去,则需要在返回值的末尾使用as const,标记这个返回值是个常量,否则返回的值将被推断成联合类型。

const useInfo = () => {
  const [age, setAge] = useState(0);

  return [age, setAge] as const; // 类型为一个元组,[number, React.Dispatch<React.SetStateAction<number>>]
};

redux相关

对于action的定义,我们可以使用官方暴露的AnyAction,放宽对于action内部键值对的限制,如下:

import { AnyAction } from "redux";

const DEF_STATE = {
  count: 0,
  type: 'integer'
};

// 使用redux的AnyAction放宽限制
function countReducer(state = DEF_STATE, action: AnyAction) {
  switch (action.type) {
    case "INCREASE_COUNT":
      return {
        ...state,
        count: state.count + 1,
      };
    case "DECREASE_COUNT":
      return {
        ...state,
        count: state.count - 1,
      };
    default:
      return state;
  }
}

export default countReducer;

规约

  1. 子组件的入参命名为[组件名]Props,如:
// 比如当前组件名为InfoCard
export interface InfoCardProps {
  name: string;
  age: number;
}
  1. interface接口类型以大写开头;
  2. 为后端接口的出入参书写interface,同时使用利于编辑器提示的jsdoc风格做注释,如:
export interface GetUserInfoReqParams {
    /** 名字 */
    name: string;
    /** 年龄 */
    age: number;
    /** 性别 */
    gender: string;
}

其他

键名或键值不确定如何处理?

// 表示键名不确定,键值限制为number类型
export interface NotSureAboutKey {
  [key: string]: number;
}

// 当键名键值都不确定时,以下接口对任何对象都是适用的
export interface AllNotSure {
  [key: string]: any;
}

如何在接口中使用泛型变量?

所谓泛型,就是预定义类型。它的目的是:达到类型定义的局部灵活,提高复用性。我们通常会在接口中使用泛型,如:

// 通常,我们会为接口的泛型变量指定一个默认类型
interface IHuman<T = unknown> {
  name: string;
  age: number;
  gender: T;
}

// 其他地方使用时
const youngMan: IHuman<string> = {
    name: 'zhangsan',
    age: 18,
    gender: 'male'
}

TypeScript在React项目中的使用总结的更多相关文章

  1. TypeScript在react项目中的实践

    前段时间有写过一个TypeScript在node项目中的实践. 在里边有解释了为什么要使用TS,以及在Node中的一个项目结构是怎样的. 但是那仅仅是一个纯接口项目,碰巧赶上近期的另一个项目重构也由我 ...

  2. 深入浅出TypeScript(5)- 在React项目中使用TypeScript

    前言 在第二小节中,我们讨论了利用TypeScript创建Web项目的实现,在本下节,我们讨论一下如何结合React创建一个具备TypeScript类型的应用项目. 准备 Webpack配置在第二小节 ...

  3. React项目中使用Mobx状态管理(二)

    并上一节使用的是普通的数据状态管理,不过官方推荐使用装饰器模式,而在默认的react项目中是不支持装饰器的,需要手动启用. 官方参考 一.添加配置 官方提供了四种方法, 方法一.使用TypeScrip ...

  4. 基于 React 封装的高德地图组件,帮助你轻松的接入地图到 React 项目中。

    react-amap 这是一个基于 React 封装的高德地图组件,帮助你轻松的接入地图到 React 项目中. 文档实例预览: Github Web | Gitee Web 特性 ️ 自动加载高德地 ...

  5. 了解CSS in JS(JSS)以及在React项目中配置并使用JSS

    目录 认识JSS 什么是JSS JSS 的常见实现 JSS 的好处与坏处 好处 坏处 使用模块化CSS实现JSS 安装插件 在React项目中的tsconfig.json中添加配置 vscode项目中 ...

  6. 如何在非 React 项目中使用 Redux

    本文作者:胡子大哈 原文链接:https://scriptoj.com/topic/178/如何在非-react-项目中使用-redux 转载请注明出处,保留原文链接和作者信息. 目录 1.前言 2. ...

  7. 如何优雅地在React项目中使用Redux

    前言 或许你当前的项目还没有到应用Redux的程度,但提前了解一下也没有坏处,本文不会安利大家使用Redux 概念 首先我们会用到哪些框架和工具呢? React UI框架 Redux 状态管理工具,与 ...

  8. react项目中实现元素的拖动和缩放实例

    在react项目中实现此功能可借助 react-rnd 库,文档地址:https://github.com/bokuweb/react-rnd#Screenshot .下面是实例运用: import ...

  9. React项目中实现右键自定义菜单

    最近在react项目中需要实现一个,右键自定义菜单功能.找了找发现纯react项目里没有什么工具可以实现这样的功能,所以在网上搜了搜相关资料.下面我会附上完整的组件代码. (注:以下代码非本人原创,具 ...

随机推荐

  1. C++算法代码——阿克曼函数

    题目来自: 题目描述 阿克曼( Ackmann) 函数 A(x, y) 中, x, y 定义域是非负整数, 函数值定义为: 输入 输入两个数,表示m和n. 两个数均不超过10. 输出 输出一个数,表示 ...

  2. Linux/UNIX编程如何保证文件落盘

    本文转载自Linux/UNIX编程如何保证文件落盘 导语 我们编写程序write数据到文件中时,其实数据不会立马写入磁盘,而是会经过层层缓存.每层缓存都有自己的刷新时机,每层缓存都刷新后才会写入磁盘. ...

  3. [Python学习笔记]爬虫

    要使用Python 抓取网页,首先我们要学习下面四个模块: 包 作用 webbrowser 打开浏览器获取指定页面: requests 从因特网下载文件和网页: Beautiful Soup 解析HT ...

  4. RxHttp - 轻量级、可扩展、易使用、完美兼容MVVM、MVC架构的网络封装类库

    前言 RxHttp是基于RxJava2+Retrofit 2.9.0+OkHttp 4.9.0实现的轻量级,完美兼容MVVM架构的网络请求封装类库,小巧精致,简单易用,轻轻松松搞定网络请求. GitH ...

  5. Linux+Tomcat+Jdk1.8+jenkins环境搭建

    1.下载jdk的rpm安装包,这里以jdk-8u191-linux-x64.rpm为例进行说明 下载地址:https://www.oracle.com/technetwork/java/javase/ ...

  6. .NET并发编程-数据并行

    本系列学习在.NET中的并发并行编程模式,实战技巧 内容目录 数据并行Fork/Join模式PLINQ 本小节开始学习数据并行的概念模式,以及在.NET中数据并行的实现方式.本系列保证最少代码呈现量, ...

  7. 185. 部门工资前三高的所有员工 + 多表联合 + join + dense_rank()

    185. 部门工资前三高的所有员工 LeetCode_MySql_185 题目描述 方法一:使用join on # Write your MySQL query statement below sel ...

  8. CCF(URL映射:80分):字符串处理+模拟

    URL映射 CCF201803-3 #include<iostream> #include<cstdio> #include<cstring> #include&l ...

  9. Hi3559AV100 NNIE RFCN开发:V4L2->VDEC->VPSS->NNIE->VGS->VO系统整体动态调试实现

    下面随笔将给出Hi3559AV100 NNIE RFCN开发:V4L2->VDEC->VPSS->NNIE->VGS->VO系统整体动态调试实现,最终的效果是:USB摄像 ...

  10. FreeBSD 如何安装软件

    1:概括FreeBSD捆绑了丰富的系统工具集合作为基础系统的一部分.此外,FreeBSD提供了两种用于安装第三方软件的补充技术:FreeBSD Ports Collection,用于从源代码安装,以及 ...