You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现类型安全的React自定义Hook?解决参数校验问题

自定义Hook类型安全优化方案

问题描述

调用自定义函数createUser时,传入数字而非字符串不会触发类型错误,遗漏必填参数也没有IDE提示。调用代码如下:

const [userState, createUser] = useCreateUser();
...
<div
  onClick={(): void => {
    createUser({
      email: 'test796420@gmail.com',
      name: 'test1',
      password: 'topSecret!',
      username: 'testuser1',
    });
  }}
>
  createUser
</div>

自定义Hook实现代码:

import { useState } from 'react';

interface CreateUserShape {
  email: string;
  name: string;
  password: string;
  referrersCode: string;
  username: string;
}

const useCreateUser = (initialState = {}): any => {
  const [state, setState] = useState(initialState);

  const createUser = async (user: CreateUserShape): Promise<void> => {
    if (user.email && user.password) {
      const method = 'POST';
      const redirect = 'follow';
      const headers = new Headers();
      const body = JSON.stringify(user);
      const url =
        'https://my-fancy-app.ondigitalocean.app/api/v1/onboarding/createUser';
      headers.append('Content-Type', 'application/json');
      const res = await fetch(`${url}`, {
        method,
        headers,
        redirect,
        body,
      });
      const response = await res.json();
      setState({ response });
    }
  };

  return [state, createUser];
};
export { useCreateUser };

优化方案

核心问题是useCreateUser返回类型设为any,导致TypeScript无法推断createUser的类型;同时initialState默认值为{},让useState失去类型约束。按以下步骤修改:

1. 定义Hook返回值类型

创建类型别名,明确Hook返回的数组结构:

type UseCreateUserReturn = [
  { response?: unknown }, // 匹配setState存入的结构
  (user: CreateUserShape) => Promise<void>
];

2. 给useCreateUser指定返回类型和参数类型

将useCreateUser的返回类型从any改为上面定义的UseCreateUserReturn,同时给initialState指定类型:

const useCreateUser = (initialState: { response?: unknown } = {}): UseCreateUserReturn => {
  const [state, setState] = useState<{ response?: unknown }>(initialState);
  // 原有逻辑不变
  return [state, createUser];
};

3. 确保CreateUserShape的必填性

当前CreateUserShape的所有字段都是必填的,调用createUser时遗漏referrersCode会直接触发TS错误。如果某些字段可选,可在字段名后加?,比如referrersCode?: string。

修改后的完整代码

import { useState } from 'react';

interface CreateUserShape {
  email: string;
  name: string;
  password: string;
  referrersCode: string;
  username: string;
}

type UseCreateUserReturn = [
  { response?: unknown },
  (user: CreateUserShape) => Promise<void>
];

const useCreateUser = (initialState: { response?: unknown } = {}): UseCreateUserReturn => {
  const [state, setState] = useState<{ response?: unknown }>(initialState);

  const createUser = async (user: CreateUserShape): Promise<void> => {
    if (user.email && user.password) {
      const method = 'POST';
      const redirect = 'follow';
      const headers = new Headers();
      const body = JSON.stringify(user);
      const url =
        'https://my-fancy-app.ondigitalocean.app/api/v1/onboarding/createUser';
      headers.append('Content-Type', 'application/json');
      const res = await fetch(`${url}`, {
        method,
        headers,
        redirect,
        body,
      });
      const response = await res.json();
      setState({ response });
    }
  };

  return [state, createUser];
};
export { useCreateUser };

效果验证

修改后:

  • 传入非字符串类型的参数(比如email: 123)会立即触发TypeScript错误
  • 遗漏CreateUserShape中的必填字段(比如referrersCode)时,IDE会显示红色波浪线提示
  • IDE会自动补全createUser的参数字段,提升开发效率

内容的提问来源于stack exchange,提问作者Bill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 11:20:27