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

TypeScript中如何推导泛型回调函数的返回类型

问题原因

你当前的类型推导失效的核心原因是createContext函数仅定义了Provider入参的泛型T,且显式将useHook的返回值标注为any,导致ReturnType<typeof useHook>获取到的结果始终为any,完全丢失了回调返回值的类型信息。

修复后的完整代码

import { FC, createElement, useState, useMemo, createContext as _context, useContext as _useContext } from 'react';

// 新增第二个泛型R,对应useHook的返回值类型
const createContext = <T, R>(useHook: (providerProps: T) => R) => {
  // 给React.createContext指定泛型为R,用类型断言做初始值占位
  const ctx = _context({} as R);

  const Provider: FC<T & { children?: React.ReactNode }> = ({ children, ...props }) => {
    const value = useHook(props as T);
    return createElement(ctx.Provider, { value }, children);
  };

  const useContext = () => _useContext(ctx);

  const createProvider = (displayName: string) => {
    Provider.displayName = displayName;
    return Provider;
  };

  return {
    useContext,
    createProvider,
  };
};

const ctx = createContext(({ _theme }: { _theme: 'light' | 'dark' }) => {
  const [theme, setTheme] = useState(_theme);
  return useMemo(() => ({ theme, setTheme }), [theme]);
});

export const AppThemeProvider = ctx.createProvider('AppThemeProvider');

const useAppTheme = () => {
  // 此时theme会自动推导为 'light' | 'dark' 类型,setTheme类型也完全正确
  const { theme } = ctx.useContext();
  return theme;
};

核心修改点

  • 为createContext新增第二个泛型参数R,用来对应你传入的自定义hook的返回值类型,TS会根据你传入的回调自动推导R的类型,不需要手动声明
  • 将useHook的返回值类型从any改为泛型R,保留完整类型信息
  • 创建原始Context时指定泛型为R,避免默认的空对象类型干扰后续类型推导
  • 不需要额外的as ReturnType断言,Context返回值类型会自动和你传入的hook返回值完全对齐

可选增强

如果需要避免在Provider外使用useContext导致的取值错误,可以给useContext加一层运行时判断:

const useContext = () => {
  const context = _useContext(ctx);
  if (Object.keys(context).length === 0) {
    throw new Error('useContext must be used within the corresponding Provider');
  }
  return context;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 03:36:02