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

封装react-query的useMutation时TypeScript类型推断异常问题

问题描述

封装react-query的useMutation为自定义钩子时,初始代码TypeScript能正确推断类型:

function myCustomMutation() {
    return useMutation({
        mutationFn: (variables: CustomVariablesType): Promise<CustomResponseType> {
            // 业务逻辑
        }
    })
}

但当尝试允许传入额外的react-query配置,引入UseMutationOptions类型后,出现类型错误:

import { useMutation, UseMutationOptions } from 'react-query';

function myCustomMutation(config: UseMutationOptions) {
    return useMutation({
        ...config,
        mutationFn: (variables: CustomVariablesType): Promise<CustomResponseType> {
            // 业务逻辑
        }
    })
}

错误提示:

Argument of type '{ useErrorBoundary?: boolean | ((error: unknown) => boolean) | undefined; mutationFn: ((variables: CustomVariablesType) => Promise) | MutationFunction<unknown, void>; mutationKey?: MutationKey | undefined; ... 6 more ...; meta?: MutationMeta | undefined; }' is not assignable to parameter of type 'MutationKey'

看起来TypeScript选错了useMutation的重载。

将配置单独提取指定类型后,又出现新错误:

import { useMutation, UseMutationOptions } from 'react-query';

function myCustomMutation(config: UseMutationOptions) {
    const newConfig:UseMutationOptions = {
        ...config,
        mutationFn: (variables: CustomVariablesType): Promise<CustomResponseType> {
            // 业务逻辑
        }
    };

    return useMutation(newConfig);
}

错误提示:

Type '(variables: CustomVariablesType): Promise' is not assignable to type 'MutationFunction<unknown, void>'

查看useMutation的类型声明:

declare function useMutation<TData = unknown, TError = unknown, TVariables = void, TContext = unknown>(options: UseMutationOptions<TData, TError, TVariables, TContext>): UseMutationResult<TData, TError, TVariables, TContext>;

其中UseMutationOptions的mutationFn类型为MutationFunction<TData, TVariables>,推测是因为未传入泛型参数,UseMutationOptions使用了默认的unknown和void类型导致的,需要解决如何在允许传入自定义配置的同时,让TypeScript正确推断类型。

解决方案

1. 显式指定基础泛型参数

为自定义钩子的UseMutationOptions明确指定你的业务类型,同时用Omit排除mutationFn(避免外部覆盖内部固定的函数逻辑):

import { useMutation, UseMutationOptions, UseMutationResult } from 'react-query';

// 提前定义你的业务类型
type CustomVariablesType = { /* 变量类型定义 */ };
type CustomResponseType = { /* 响应类型定义 */ };

function myCustomMutation(
  config?: Omit<UseMutationOptions<CustomResponseType, unknown, CustomVariablesType>, 'mutationFn'>
): UseMutationResult<CustomResponseType, unknown, CustomVariablesType> {
  return useMutation({
    ...config,
    mutationFn: (variables: CustomVariablesType): Promise<CustomResponseType> => {
      // 你的业务逻辑,比如API请求
      return fetch('/api/your-endpoint', {
        method: 'POST',
        body: JSON.stringify(variables)
      }).then(res => res.json());
    }
  });
}
  • 显式指定泛型后,TypeScript会正确识别mutationFn的参数和返回值类型,不会再使用默认的unknown和void
  • Omit确保外部传入的配置无法覆盖内部的mutationFn,保证钩子的核心逻辑固定

2. 允许自定义错误和上下文类型(可选)

如果需要让调用方自定义错误类型(TError)和上下文类型(TContext),可以把自定义钩子改成泛型函数:

import { useMutation, UseMutationOptions, UseMutationResult } from 'react-query';

type CustomVariablesType = { /* 变量类型定义 */ };
type CustomResponseType = { /* 响应类型定义 */ };

function myCustomMutation<
  TError = unknown,
  TContext = unknown
>(
  config?: Omit<UseMutationOptions<CustomResponseType, TError, CustomVariablesType, TContext>, 'mutationFn'>
): UseMutationResult<CustomResponseType, TError, CustomVariablesType, TContext> {
  return useMutation({
    ...config,
    mutationFn: (variables: CustomVariablesType): Promise<CustomResponseType> => {
      // 业务逻辑
      return fetch('/api/your-endpoint', {
        method: 'POST',
        body: JSON.stringify(variables)
      }).then(res => res.json());
    }
  });
}

这样调用方可以根据需求传入自定义的错误和上下文类型,同时保持mutationFn的类型固定。

3. 解决重载匹配问题

之前出现的重载选错问题,本质是未指定泛型的UseMutationOptions会被TypeScript误判为兼容MutationKey的类型(useMutation有一个直接传mutationKey的重载)。显式指定泛型参数后,TypeScript会自动匹配接收UseMutationOptions的正确重载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 07:40:34