React + TypeScript 项目中常见类型

38 阅读3分钟

在 React + TypeScript 开发中,理解以下核心类型对编写类型安全的组件非常重要。以下是常见 React 类型的详细解释:


1. ReactElement

ReactElement 表示一个 React 元素,它是 React 应用中最基本的构建块。一个 React 元素可以是一个 HTML 标签(如 <div><p> 等)或者是一个自定义组件。表示虚拟 DOM 的基本单元,通常由 JSX 转换而来

用例:

import React from 'react';

const element: ReactElement = <div>Hello, World!</div>;

2. ReactNode

ReactNode 是一个更宽泛的类型,它可以表示任何可以在 JSX 中渲染的内容。这包括 ReactElement、字符串、数字、数组、null undefined 和 boolean 等。

type ReactNode =
  | ReactChild
  | ReactFragment
  | ReactPortal
  | boolean
  | null
  | undefined;

用例:

function Container({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>;
}

import React, { ReactNode } from 'react';

function renderContent(content: ReactNode) {
  return <div>{content}</div>;
}

renderContent(<p>Paragraph</p>); // ReactElement
renderContent('Hello'); // 字符串
renderContent(123); // 数字
renderContent([<span>Item 1</span>, <span>Item 2</span>]); // 数组
renderContent(null); // null
renderContent(false); // boolean

3. JSX.Element

与 ReactElement 类似,但更严格地表示 JSX 表达式的结果

declare namespace JSX {
  interface Element extends React.ReactElement {}
}

4. ReactChild

ReactChild 是 ReactNode 的子集,它只包括 ReactElement、字符串和数字。

import React, { ReactChild } from 'react';

function renderChild(child: ReactChild) {
  return <div>{child}</div>;
}

renderChild(<p>Paragraph</p>); // ReactElement
renderChild('Hello'); // 字符串
renderChild(123); // 数字


5. ReactFragment

ReactFragment 表示一个 React 片段,它允许你在不添加额外 DOM 节点的情况下将多个子元素组合在一起。ReactFragment 可以是一个空标签 <></> 或者 <React.Fragment></React.Fragment>

import React, { ReactFragment } from 'react';

const fragment: ReactFragment = (
  <>
    <p>First</p>
    <p>Second</p>
  </>

6. React.ComponentType

表示类组件或函数组件的类型,React.ComponentType 表示一个 React 组件类型,它可以是一个函数组件或类组件。

type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;

用例(HOC):

function withLogger<T>(WrappedComponent: React.ComponentType<T>) {
  return (props: T) => {
    console.log('Rendered!');
    return <WrappedComponent {...props} />;
  };
}

7. FunctionComponent (FC)

React.ComponentType 表示一个 React 组件类型,它可以是一个函数组件或类组件。 推荐写法:

const MyComponent: React.FC<MyProps> = ({ title }) => {
  return <div>{title}</div>;
};

8. PropsWithChildren

自动包含 children 属性的 props 类型助手,ReactPropsWithChildren 它用于为组件的 props 类型添加 children 属性。组件需要显式读取 children 时,方便定义。

用例:

import React, { ReactPropsWithChildren } from 'react';

interface MyComponentProps extends ReactPropsWithChildren {
  title: string;
}

function MyComponent({ title, children }: MyComponentProps) {
  return (
    <div>
      <h1>{title}</h1>
      {children}
    </div>
  );
}

9. React.ReactElement vs JSX.Element vs ReactNode

类型包含内容典型使用场景
ReactElementJSX 创建的单个元素createElement 返回值
JSX.Element同 ReactElement,但类型更严格函数组件返回值类型
ReactNode所有可渲染内容组件 children 类型定义

10. 合成事件类型

常见事件处理类型:

React.ChangeEvent<HTMLInputElement>   // 输入框变更
React.MouseEvent<HTMLButtonElement>   // 鼠标事件
React.KeyboardEvent<HTMLInputElement> // 键盘事件
React.FormEvent<HTMLFormElement>      // 表单提交

用例:

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  console.log(e.target.value);
};

11. Ref 相关类型

React.RefObject<T>       // useRef 创建的不可变 ref 对象
React.MutableRefObject<T> // 可变 ref(需指定泛型参数)
React.LegacyRef<T>       // 兼容旧版 ref 类型

用例:

const inputRef = useRef<HTMLInputElement>(null);

12. Context 类型

React.Context<T>                    // 上下文对象类型
React.ProviderProps<ContextType>    // Provider 属性类型
React.ConsumerProps<ContextType>    // Consumer 属性类型

用例:

interface ThemeContextType {
  color: string;
  toggle: () => void;
}

const ThemeContext = React.createContext<ThemeContextType | null>(null);

最佳实践建议:

  1. 优先使用 ReactNode 作为 children 类型
  2. 避免过度使用 FC,推荐显式声明 props 类型
  3. 事件处理函数优先使用合成事件类型
  4. 使用 ComponentProps 提取组件 props 类型:
type ButtonProps = React.ComponentProps<typeof Button>;

预祝:代码写的爽,面试答的棒各位~