TypeScript异步函数返回类型问题:void与IVerifiedCity冲突
解决TypeScript辅助函数返回类型冲突问题
核心问题分析
你遇到的错误源于TypeScript的类型规则:void仅能作为函数的直接返回类型或特定泛型变量使用,不能放在Promise的泛型联合类型中。而你的函数逻辑试图同时返回业务数据(IVerifiedCity)和触发Express错误流转(调用next(new AppError())),这直接导致了类型声明的冲突。
两种可行解决方案
方案1:分离辅助函数与错误处理(推荐,符合MVC职责分离)
让辅助函数仅负责数据验证并返回结果/空值,将错误处理(调用next)交给上层中间件,既清晰又符合分层架构:
// 辅助函数:专注验证逻辑,返回数据或null async function verifyCityInDb(cityId: string): Promise<IVerifiedCity | null> { const city = await CityModel.findById(cityId); if (!city) { return null; } return { id: city._id, name: city.name } as IVerifiedCity; } // 中间件:处理错误流转和请求上下文挂载 async function cityMiddleware(req: Request, res: Response, next: NextFunction) { const city = await verifyCityInDb(req.params.cityId); if (!city) { return next(new AppError('City not found', 404)); } req.city = city; // 将验证后的数据挂载到请求对象 next(); }
方案2:在错误路径终止函数执行
如果坚持在辅助函数中调用next,可以在调用next后返回一个永远不会解析的Promise,让TypeScript认定函数始终返回IVerifiedCity类型:
async function verifyCityInDb(cityId: string, next: NextFunction): Promise<IVerifiedCity> { const city = await CityModel.findById(cityId); if (!city) { next(new AppError('City not found', 404)); // 返回pending状态的Promise,终止函数执行流,满足TS类型要求 return new Promise(() => {}); } return { id: city._id, name: city.name } as IVerifiedCity; }
也可以用抛出异常的方式(该异常不会被Express处理,仅用于TypeScript类型推断):
async function verifyCityInDb(cityId: string, next: NextFunction): Promise<IVerifiedCity> { const city = await CityModel.findById(cityId); if (!city) { next(new AppError('City not found', 404)); throw new Error('City verification failed'); } return { id: city._id, name: city.name } as IVerifiedCity; }
关键提醒
避免在函数中混合返回业务数据和触发错误流转,这不仅会导致类型混乱,也违背了单一职责原则。TypeScript对void的限制本质是为了明确函数语义:void代表无返回值,而Promise的泛型应该是函数成功时返回的具体值。
内容的提问来源于stack exchange,提问作者Kévin WITZ
相关产品推荐
相关产品推荐

