[TOC]

在react中使用TypeScript

TypeScript在react中两种类型文件:

1、.tsx文件:编写程序代码的地方,既包含类型信息又可执行代码

2、.d.ts文件:只包含类型信息的类型声明文件。不会生成 .js 文件,仅用于提供类型信息,在.d.ts文件中不允许出现可执行的代码,只用于提供类型

如果要为 JS 库提供类型信息,要使用 .d.ts 文件

1. props、state等变量属性声明接口

interface Base {
  // 基本类型
  message: string;
  count: number;
  disabled: boolean;
  names: string[]; // 数组类型
  /** 用「联合类型」限制为下面两种「字符串字面量」类型 */
  status: 'waiting' | 'success';
}
interface Props {
  /** 如果你不需要用到具体的属性 可以这样模糊规定是个对象 ❌ 不推荐 */
  obj: object; // 或 obj2: {}
  /** 拥有具体属性的对象类型 ✅ 推荐 */
  obj3: { id: string; title: string };
  /** 对象数组 😁 常用 */
  objArr: Array<{ id: string; title: string }>;
  /** key 可以为任意 string,值限制为 MyTypeHere 类型 */
  dict1: {
    [key: string]: Base;
  };
  // 基本上和 dict1 相同,用了 TS 内置的 Record 类型。
  dict2: Record<string, Base>;
  /** 任意的函数类型 ❌ 不推荐 不能规定参数以及返回值类型 */
  onSomething: Function;
  /** 没有参数的函数 不需要返回值 😁 常用 */
  onClick: () => void;
  /** 带函数的参数 😁 非常常用 */
  onChange: (id: number) => void;
  /** 另一种函数语法 参数是 React 的按钮事件 😁 非常常用 */
  onClickOne: (event: React.MouseEvent<HTMLButtonElement>) => void;
  /** 可选参数类型 😁 非常常用 */
  optional?: Base;

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

2. 类组件声明

// props 和 state 都规定具体的
type IPrps = { message: string; };
type IState = { count: number;  };
class App extends React.Component<IPrps, IState> {}

// props 和 state 都是任何数据的
type P = any;
type S = any;
class App extends PureComponent<P, S> {}

// props是泛型,在调用的时候确认,state接口使用上面的
class App<P> extends PureComponent<P, state> {}
// 使用组件
type IProps = { name: string; age: number; };
<App<IProps> name="React" age={18} />;          // Success
<App<IProps> name="TypeScript" age="hello" />;  // Error

React 官网对于 Component 的类型定义如下:

interface Component<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> { }

3. 函数组件声明

import React from 'react';
interface IProps { name: string }
const App = (props: IProps) => {}
// 或
const App = ({name}: IProps) => {}
// 或 FC:函数组件
// type React.FC<P = {}> = React.FunctionComponent<P>
const App: React.FC<IProps> = (props) => {}

如果我们在定义组件时不知道props的类型,只有调用时才知道,那就还是用泛型来定义props的类型:

// 定义组件
function App<P>(props: P) {}
// 使用组件
type IProps = { name: string; age: number; };
<App<IProps> name="React" age={18} />;          // Success
<App<IProps> name="TypeScript" age="hello" />;  // Error

4. hooks组件

4.1 useState

 interface Item { target: string; }
// 1. 默认情况下,React会为根据设置的state的初始值来自动推导state以及更新函数的类型:
const [name, setName] = useState('jack');
// 2. 已知类型
const [count, setCount] = useState<number>(1);
const [item, setItem] = useState<Item | null>(null);
// 3. 初始值为null,需要显示地声明
const [count, setCount] = useState<number | null>(null);

4.2 useRef、useCallback、useMemo

const nameInput = React.useRef<HTMLInputElement>(null);
const ref = React.useRef<HTMLElement | null>(null);
// useCallback
const memoizedCallback = useCallback(
  // 如果不给参数定义类型,会报错
  (a: number) => { add(a, b); },
  [b]
);
// useMemo
const calculatedValue = useMemo<number>(() => a ** 2, [a]);

4.3 useReducer

type AuthState = {};
type Action =
  | { type: "FETCH_SUCCESS"; payload: any }
  | { type: "FETCH_ERROR"; payload: string };

export function reducer(state: AuthState, action: Action): AuthState {
  switch (action.type) {
    case "FETCH_SUCCESS":
      return {
        ...state,
        one: action.payload
      };
    case "FETCH_ERROR":
      ....
    default:
      return state;
  }
}

5. 事件处理、HTML标签类型

待完成:

https://juejin.cn/post/7021674818621669389#heading-19

https://juejin.cn/post/6844903999351554056#heading-5

参考资料

Last Updated: 11/22/2024, 3:19:16 PM