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

TypeScript泛型重载报错:找不到TResponse/TData及接口设计疑问

问题1:"Cannot find name 'TResponse'/'TData'" 错误原因及修复

你给appFetch指定类型AppFetchOverload<TResponse, TData>时,TResponse和TData没有被声明为泛型参数。AppFetchOverload是泛型接口,但直接使用时必须明确泛型作用域,正确做法是将appFetch定义为泛型函数并结合重载签名:

type TransformFn<TResponse, TData> = (arg0: TResponse) => TData;

interface AppFetchInit extends RequestInit {
    errMsg?: string;
    transformFn?: undefined;
}

interface AppFetchInitWithTransformFn<TResponse, TData> extends Omit<AppFetchInit, 'transformFn'> {
    transformFn: TransformFn<TResponse, TData>;
}

// 重载签名
async function appFetch<TResponse>(apiURI: string, init?: AppFetchInit): Promise<TResponse>;
async function appFetch<TResponse, TData>(apiURI: string, init: AppFetchInitWithTransformFn<TResponse, TData>): Promise<TData>;

// 实现签名
async function appFetch<TResponse, TData = TResponse>(
    apiURI: string,
    { errMsg, transformFn, ...init }: AppFetchInit | AppFetchInitWithTransformFn<TResponse, TData> = {} as AppFetchInit
) {
    const response = await fetch(apiURI, init);

    if (!response.ok)
        throw new Error(errMsg ?? `Fetching ${apiURI} failed: ${response.statusText}`);

    const responseJson = (await response.json()) as TResponse;

    return (transformFn ? transformFn(responseJson) : responseJson) as TData;
}

export { appFetch };

核心修改点:

  • 用泛型函数重载替代泛型接口赋值,让TResponse和TData拥有正确的作用域
  • 实现签名的参数类型覆盖两种初始化接口,给默认值添加类型断言避免解构错误
  • 返回值添加类型断言,帮助TypeScript正确推导返回类型
问题2:接口设计与重载匹配的疑问

你当前的接口设计不会导致返回类型错误:AppFetchInit限定transformFn只能是可选的undefined,AppFetchInitWithTransformFn要求必须传入有效的transformFn,TypeScript会根据参数自动匹配对应重载:

  • 不传入transformFn或显式传transformFn: undefined时,匹配第一个重载,返回TResponse类型
  • 传入有效transformFn时,匹配第二个重载,返回TData类型

如果想简化设计,可以合并成单个接口,通过类型工具区分重载场景:

type TransformFn<TResponse, TData> = (arg0: TResponse) => TData;

interface AppFetchInit<TResponse, TData> extends RequestInit {
    errMsg?: string;
    transformFn?: TransformFn<TResponse, TData>;
}

async function appFetch<TResponse>(apiURI: string, init?: Omit<AppFetchInit<TResponse, never>, 'transformFn'>): Promise<TResponse>;
async function appFetch<TResponse, TData>(apiURI: string, init: Required<Pick<AppFetchInit<TResponse, TData>, 'transformFn'>> & Omit<AppFetchInit<TResponse, TData>, 'transformFn'>): Promise<TData>;

async function appFetch<TResponse, TData = TResponse>(
    apiURI: string,
    { errMsg, transformFn, ...init }: AppFetchInit<TResponse, TData> = {} as AppFetchInit<TResponse, TData>
) {
    const response = await fetch(apiURI, init);

    if (!response.ok)
        throw new Error(errMsg ?? `Fetching ${apiURI} failed: ${response.statusText}`);

    const responseJson = (await response.json()) as TResponse;

    return (transformFn ? transformFn(responseJson) : responseJson) as TData;
}

export { appFetch };

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 03:58:12