使用条件类型处理Promise返回类型:API调用类型推导异常
解决方案:MongoDB API 类型推导问题
问题根源
你的问题出在泛型参数的约束范围和条件类型的推导逻辑上:当泛型T被约束为boolean时,TypeScript会将其解析为包含true和false的联合类型,导致Schema<T>最终推导为{prop1: string} | {prop1: 对象}的联合类型,而非你期望的单一类型。
方案1:使用函数重载(推荐)
函数重载能明确对应不同参数值的返回类型,避免联合类型的歧义,是最直观可靠的解决方式:
// 基础类型定义 type ObjectId = string; type PopulatedProp = { id: ObjectId; name: string }; // 拆分两种状态的Schema type UnpopulatedSchema = { prop1: ObjectId }; type PopulatedSchema = { prop1: PopulatedProp }; // 函数重载声明 async function callApi(): Promise<UnpopulatedSchema[]>; async function callApi(populate: false): Promise<UnpopulatedSchema[]>; async function callApi(populate: true): Promise<PopulatedSchema[]>; // 函数实现 async function callApi(populate: boolean = false): Promise<(UnpopulatedSchema | PopulatedSchema)[]> { // 模拟API调用逻辑 const res = await fetch('/api/data'); return res.json(); } // 调用示例 const unpopulatedData = callApi(); // 类型:UnpopulatedSchema[] const populatedData = callApi(true); // 类型:PopulatedSchema[] const mixedData = callApi(Math.random() > 0.5); // 类型:(UnpopulatedSchema | PopulatedSchema)[]
方案2:约束泛型为字面量类型
如果坚持使用条件类型,需要将泛型参数约束为true | false字面量(而非宽泛的boolean),让TypeScript能精准匹配条件分支:
type ObjectId = string; type PopulatedProp = { id: ObjectId; name: string }; // 条件类型:仅接受true/false字面量 type Schema<T extends true | false> = T extends true ? { prop1: PopulatedProp } : { prop1: ObjectId }; // 泛型函数:约束T为true/false字面量 async function callApi<T extends true | false>(populate: T): Promise<Schema<T>[]> { const res = await fetch('/api/data'); // 运行时无法保证类型,需添加类型断言 return res.json() as Schema<T>[]; } // 调用示例 const populatedData = callApi(true); // 类型:{ prop1: PopulatedProp }[] const unpopulatedData = callApi(false); // 类型:{ prop1: ObjectId }[]
关键说明
- 函数重载的优势在于无需额外类型断言,类型推导更清晰,尤其适合对外暴露的API函数。
- 字面量泛型约束需要配合类型断言,因为TypeScript无法在编译时验证API返回的实际数据结构,断言是为了告诉编译器“运行时数据符合预期类型”。
内容的提问来源于stack exchange,提问作者Echo
相关产品推荐
相关产品推荐

