• TypeScript在React中的优雅写法


    目录

    前言

    组件 Props

    基础类型

    对象类型

    函数类型

    React 相关类型

    React元素相关

    原生DOM相关

    类组件

    函数组件

    与hooks的结合

    useState

    userReducer

    useRef

    自定义 hook

    React合成事件相关

    Event 事件对象类型

    扩展组件的 Props

    redux相关

    第三方库

    规约

    其他

    前言

    其实如果运用熟练的话,TS 只是在第一次开发的时候稍微多花一些时间去编写类型,后续维护、重构的时候就会发挥它神奇的作用了,还是非常推荐长期维护的项目使用它的。

    组件 Props

    先看几种定义 Props 经常用到的类型:

    基础类型

    1. type BasicProps = {
    2. message: string;
    3. count: number;
    4. disabled: boolean;
    5. /** 数组类型 */
    6. names: string[];
    7. /** 用「联合类型」限制为下面两种「字符串字面量」类型 */
    8. status: "waiting" | "success";
    9. };

    对象类型

    1. type ObjectOrArrayProps = {
    2. /** 如果你不需要用到具体的属性 可以这样模糊规定是个对象 ❌ 不推荐 */
    3. obj: object;
    4. obj2: {}; // 同上
    5. /** 拥有具体属性的对象类型 ✅ 推荐 */
    6. obj3: {
    7. id: string;
    8. title: string;
    9. };
    10. /** 对象数组 😁 常用 */
    11. objArr: {
    12. id: string;
    13. title: string;
    14. }[];
    15. /** key 可以为任意 string,值限制为 MyTypeHere 类型 */
    16. dict1: {
    17. [key: string]: MyTypeHere;
    18. };
    19. dict2: RecordMyTypeHere>; // 基本上和 dict1 相同,用了 TS 内置的 Record 类型。
    20. }
    1. //通过接口定义相应的结构
    2. interface Item {
    3. name: string,
    4. icon: string,
    5. url: string,
    6. status:boolean,
    7. initShow:boolean,
    8. copanyStatus:boolean
    9. }
    1. interface MyObject {
    2. [key: string]: any;
    3. }

    函数类型

    1. // 基本语法
    2. interface InterfaceName {
    3.  (param1: parameterType1,param2:parameterType2... ): returnType;
    4. }
    5. // type定义
    6. type FunctionProps = {
    7. /** 任意的函数类型 ❌ 不推荐 不能规定参数以及返回值类型 */
    8. onSomething: Function;
    9. /** 没有参数的函数 不需要返回值 😁 常用 */
    10. onClick: () => void;
    11. /** 带函数的参数 😁 非常常用 */
    12. onChange: (id: number) => void;
    13. /** 另一种函数语法 参数是 React 的按钮事件 😁 非常常用 */
    14. onClick(event: React.MouseEvent<HTMLButtonElement>): void;
    15. (name:string):string;
    16. /** 可选参数类型 😁 非常常用 */
    17. optional?: OptionalType;
    18. }

    React 相关类型

    1. export declare interface AppProps {
    2. children1: JSX.Element; // ❌ 不推荐 没有考虑数组
    3. children2: JSX.Element | JSX.Element[]; // ❌ 不推荐 没有考虑字符串 children
    4. children4: React.ReactChild[]; // 稍微好点 但是没考虑 null
    5. children: React.ReactNode; // ✅ 包含所有 children 情况
    6. functionChildren: (name: string) => React.ReactNode; // ✅ 返回 React 节点的函数
    7. style?: React.CSSProperties; // ✅ 推荐 在内联 style 时使用
    8. // ✅ 推荐原生 button 标签自带的所有 props 类型
    9. // 也可以在泛型的位置传入组件 提取组件的 Props 类型
    10. props: React.ComponentProps<"button">;
    11. // ✅ 推荐 利用上一步的做法 再进一步的提取出原生的 onClick 函数类型
    12. // 此时函数的第一个参数会自动推断为 React 的点击事件类型
    13. onClickButton:React.ComponentProps<"button">["onClick"]
    14. }

    React元素相关

    React元素相关的类型主要包括ReactNode、ReactElement、JSX.Element。

    ReactNode。表示任意类型的React节点,这是个联合类型,包含情况众多;

    ReactElement/JSX。从使用表现上来看,可以认为这两者是一致的,属于ReactNode的子集,表示“原生的DOM组件”或“自定义组件的执行结果”。

    使用示例如下:

    1. const MyComp: React.FC<{ title: string; }> = ({title}) => <h2>{title}h2>;
    2. // ReactNode
    3. const a: React.ReactNode =
    4. null ||
    5. undefined || <div>hellodiv> || <MyComp title="world" /> ||
    6. "abc" ||
    7. 123 ||
    8. true;
    9. // ReactElement和JSX.Element
    10. const b: React.ReactElement = <div>hello worlddiv> || <MyComp title="good" />;
    11. const c: JSX.Element = <MyComp title="good" /> || <div>hello worlddiv>;

    原生DOM相关

    原生的 DOM 相关的类型,主要有以下这么几个:Element、 HTMLElement、HTMLxxxElment。

    简单来说: Element = HTMLElement + SVGElement。

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

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

    类组件

    1. // Second.tsx
    2. import * as React from 'react'
    3. import SecondComponent from './component/Second1'
    4. export interface ISecondProps {}
    5. export interface ISecondState {
    6. count: number
    7. title: string
    8. }
    9. export default class Second extends React.Component<
    10. ISecondProps,
    11. ISecondState
    12. > {
    13. constructor(props: ISecondProps) {
    14. super(props)
    15. this.state = {
    16. count: 0,
    17. title: 'Second标题',
    18. }
    19. this.changeCount = this.changeCount.bind(this)
    20. }
    21. changeCount() {
    22. let result = this.state.count + 1
    23. this.setState({
    24. count: result,
    25. })
    26. }
    27. public render() {
    28. return (
    29. <div>
    30. {this.state.title}--{this.state.count}
    31. <button onClick={this.changeCount}>点击增加button>
    32. <SecondComponent count={this.state.count}>SecondComponent>
    33. div>
    34. )
    35. }
    36. }
    1. // second1.tsx
    2. import * as React from 'react'
    3. export interface ISecond1Props {
    4. count: number
    5. }
    6. export interface ISecond1State {
    7. title: string
    8. }
    9. export default class Second1 extends React.Component<
    10. ISecond1Props,
    11. ISecond1State
    12. > {
    13. constructor(props: ISecond1Props) {
    14. super(props)
    15. this.state = {
    16. title: '子组件标题',
    17. }
    18. }
    19. public render() {
    20. return (
    21. <div>
    22. {this.state.title}---{this.props.count}
    23. div>
    24. )
    25. }
    26. }

    函数组件

    1. // Home.tsx
    2. import * as React from 'react'
    3. import { useState, useEffect } from 'react'
    4. import Home1 from './component/Home1'
    5. interface IHomeProps {
    6. childcount: number;
    7. }
    8. const Home: React.FunctionComponent<IHomeProps> = (props) => {
    9. const [count, setCount] = useState < number > 0
    10. function addcount() {
    11. setCount(count + 1)
    12. }
    13. return (
    14. <div>
    15. <span>Home父组件内容数字是{count}span>
    16. <button onClick={addcount}>点击增加数字button>
    17. <Home1 childcount={count}>Home1>
    18. div>
    19. )
    20. }
    21. export default Home
    1. // Home1.tsx
    2. import * as React from 'react'
    3. interface IHome1Props {
    4. childcount: number;
    5. }
    6. const Home1: React.FunctionComponent<IHome1Props> = (props) => {
    7. const { childcount } = props
    8. return <div>Home组件1--{childcount}div>
    9. }
    10. export default Home1
    1. import React from 'react'
    2. interface Props {
    3. name: string;
    4. color: string;
    5. }
    6. type OtherProps = {
    7. name: string;
    8. color: string;
    9. }
    10. // Notice here we're using the function declaration with the interface Props
    11. function Heading({ name, color }: Props): React.ReactNode {
    12. return <h1>My Website Headingh1>
    13. }
    14. // Notice here we're using the function expression with the type OtherProps
    15. const OtherHeading: React.FC<OtherProps> = ({ name, color }) =>
    16. <h1>My Website Headingh1>

    关于 interface 或 type ,我们建议遵循 react-typescript-cheatsheet 社区提出的准则:

    • 在编写库或第三方环境类型定义时,始终将 interface 用于公共 API 的定义。
    • 考虑为你的 React 组件的 State 和 Props 使用 type ,因为它更受约束。”

    让我们再看一个示例:

    1. import React from 'react'
    2. type Props = {
    3. /** color to use for the background */
    4. color?: string;
    5. /** standard children prop: accepts any valid React Node */
    6. children: React.ReactNode;
    7. /** callback function passed to the onClick handler*/
    8. onClick: () => void;
    9. }
    10. const Button: React.FC<Props> = ({ children, color = 'tomato', onClick }) => {
    11. return <button style={{ backgroundColor: color }} onClick={onClick}>{children}button>
    12. }

    在此

  • 相关阅读:
    21、ila
    Python学习笔记--生成器
    牛客网基础知识强化巩固-周结03
    Android 12.0 开启蓝牙状态栏即显示蓝牙图标
    幻核退出 “数字藏品有何用”阶段性无解
    webpack
    SpringSecurity认证和授权流程详解
    水塘抽样(应用场景+算法步骤+算法证明+Python实现)
    最小生成树算法之 Kruskal 和 Prim
    【愚公系列】2022年12月 使用win11系统自带SSH,远程控制VMware中Liunx虚拟机系统
  • 原文地址:https://blog.csdn.net/duansamve/article/details/126767053