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

TypeScript重载签名不兼容:useTabs钩子加入setCurrentTab报错

自定义useTabs Hook的类型兼容问题

初始问题场景

当从返回接口useTabsReturnType中移除setCurrentTab属性时,代码可正常运行;但添加该属性后,触发类型不兼容报错。

初始代码

interface useTabsReturnType<T> {
  currentTab: T;
  setCurrentTab: React.Dispatch<React.SetStateAction<T>>;
}

export function useTabs(defaultValues: number): useTabsReturnType<number>;
// 报错:This overload signature is not compatible with its implementation signature.ts(2394)
export function useTabs(defaultValues: string): useTabsReturnType<string>;
export function useTabs(defaultValues?: string | number): useTabsReturnType<string | number> {
  const [currentTab, setCurrentTab] = useState(defaultValues || '');

  return {
    currentTab,
    setCurrentTab,
  };
}

修改后出现的新错误

按照Radu Diță的建议调整后,返回语句中的setCurrentTab属性触发新的类型错误:

Type 'Dispatch<SetStateAction<string | number>>' is not assignable to type 'Dispatch<SetStateAction<string>> | Dispatch<SetStateAction<number>>'.
  Type 'Dispatch<SetStateAction<string | number>>' is not assignable to type 'Dispatch<SetStateAction<string>>'.
    Type 'SetStateAction<string>' is not assignable to type 'SetStateAction<string | number>'.
      Type '(prevState: string) => string' is not assignable to type 'SetStateAction<string | number>'.
        Type '(prevState: string) => string' is not assignable to type '(prevState: string | number) => string | number'.
          Types of parameters 'prevState' and 'prevState' are incompatible.
            Type 'string | number' is not assignable to type 'string'.
              Type 'number' is not assignable to type 'string'.ts(2322)
useTabs.ts(20, 3): The expected type comes from property 'setCurrentTab' which is declared here on type 'useTabsReturnType<number> | useTabsReturnType<string>'

问题原因与解决办法

核心原因

  • 初始重载冲突:实现签名返回useTabsReturnType<string | number>,但重载签名要求返回单一类型的useTabsReturnType,TypeScript无法自动收敛联合类型到单一类型,尤其是setCurrentTab的dispatch类型存在逆变特性,导致重载不兼容。
  • Dispatch类型不兼容:Dispatch<SetStateAction<string | number>>不能赋值给Dispatch<SetStateAction<string>> | Dispatch<SetStateAction<number>>,因为dispatch函数参数是逆变的——接受更宽泛类型的dispatch,无法被当作接受更窄类型的dispatch使用。

修复代码

用泛型重构,让TypeScript自动推导类型,避免手动重载的兼容问题:

import { useState, Dispatch, SetStateAction } from 'react';

interface useTabsReturnType<T> {
  currentTab: T;
  setCurrentTab: Dispatch<SetStateAction<T>>;
}

export function useTabs<T extends string | number>(defaultValue?: T): useTabsReturnType<T> {
  const [currentTab, setCurrentTab] = useState<T>(defaultValue ?? ('') as T);

  return {
    currentTab,
    setCurrentTab,
  };
}

说明

  • 泛型T约束输入为string | number,TypeScript会根据传入的默认值自动推导返回类型。
  • defaultValue ?? ('') as T处理默认值为空的场景,保证类型匹配。
  • 移除手动重载,通过泛型实现类型安全,同时解决dispatch的逆变类型冲突问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 15:30:51