无法实现条件类型:TypeScript包装函数返回类型错误求助
问题分析与修正方案
错误原因
你的泛型约束FnT extends UnknownFnT导致TypeScript无法正确区分“无回调”场景:即使不传入callback,TypeScript仍会将FnT推断为UnknownFnT的子类型(比如默认的() => void),此时PromiseRes<FnT>会被解析为Promise<ReturnType<FnT>>,而非预期的Promise<string>,返回'ok'时自然触发类型不匹配错误。
另外原代码中callback.apply(args)的用法有误:apply的第一个参数是this上下文,第二个参数才是参数数组,正确调用应为callback.apply(null, args)或直接展开参数callback(...args)。
修正方案
使用函数重载明确两种调用场景的类型,同时简化异步逻辑实现(无需手动嵌套new Promise):
type UnknownFnT = (...args: any[]) => any; // 函数重载:定义两种调用签名 export function timePromise(ms: number): Promise<string>; export function timePromise<FnT extends UnknownFnT>( ms: number, callback: FnT, ...args: Parameters<FnT> ): Promise<ReturnType<FnT>>; // 核心实现逻辑 export async function timePromise<FnT extends UnknownFnT | undefined>( ms: number, callback?: FnT, ...args: FnT extends UnknownFnT ? Parameters<FnT> : [] ): Promise<FnT extends UnknownFnT ? ReturnType<FnT> : string> { // 等待指定毫秒数 await new Promise(resolve => setTimeout(resolve, ms)); if (callback) { // 调用回调并返回结果(支持异步回调) return await callback(...args); } // 无回调时返回固定字符串 return 'ok'; }
方案优势
- 精准类型推断:函数重载直接定义两种调用模式的类型签名,TypeScript能准确识别返回值类型:
- 仅传
ms时,返回Promise<string> - 传入
callback和参数时,返回Promise<ReturnType<FnT>>
- 仅传
- 简化异步逻辑:利用
async/await特性封装setTimeout,避免嵌套Promise的冗余写法 - 修正回调调用:
callback(...args)更直观,且符合TypeScript的类型推断规则
测试示例
// 无回调场景:返回Promise<string> timePromise(1000).then(res => { // res类型为string console.log(res); // 输出 'ok' }); // 同步回调场景:返回Promise<number> timePromise(1000, (a: number, b: number) => a + b, 1, 2).then(res => { // res类型为number console.log(res); // 输出 3 }); // 异步回调场景:返回Promise<string> timePromise(1000, async () => { await new Promise(resolve => setTimeout(resolve, 500)); return 'async result'; }).then(res => { // res类型为string console.log(res); // 输出 'async result' });
内容的提问来源于stack exchange,提问作者Kirill Kazakov
相关产品推荐
相关产品推荐

