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
相关产品推荐
相关产品推荐

