如何推断生成器产出的异步函数的返回类型?
解决TypeScript中异步生成器任务返回类型的推断问题
你遇到的问题是createSettlementSequence函数中,泛型T无法从生成器产出的异步函数自动推断为string,只能得到unknown,但J的类型能被正确推断。核心原因是当前泛型参数的声明顺序和依赖关系导致TypeScript无法反向推导T。
解决方案
调整泛型参数结构,不再单独声明T,而是通过条件类型从J中提取出对应的返回类型。这样TypeScript会先推断出J的完整类型,再自动推导T的值,同时保留J携带自定义元数据的能力。
修改后的代码
type Job<T> = () => Promise<T> export interface JobFulfilment<T, J extends Job<T>> { job: J; status: "fulfilled"; value: T; } export interface JobRejection<T, J extends Job<T>> { job: J; status: "rejected"; reason: unknown; } export type JobSettlement<T, J extends Job<T>> = | JobFulfilment<T, J> | JobRejection<T, J>; // 调整泛型参数,仅声明J,通过条件类型从J中提取T export async function* createSettlementSequence<J extends Job<any>>( createJobSequence: () => AsyncGenerator<J> ): AsyncIterable<JobSettlement<J extends Job<infer T> ? T : never, J>> { for await (const job of createJobSequence()){ try{ const value = await job(); yield { job, value, status:"fulfilled", } as JobFulfilment<J extends Job<infer T> ? T : never, J> } catch(reason){ yield { job, reason, status:"rejected" } as JobRejection<J extends Job<infer T> ? T : never, J> } } } const settlementSequence = createSettlementSequence(async function* () { yield async () => "foo" yield async () => "bar" yield async () => "baz" }) // 带元数据的场景同样能正确推断 const settlementSequenceWithMetadata = createSettlementSequence(async function* () { yield Object.assign(async () => "foo", { task: 0}) yield Object.assign(async () => "bar", { task: 1}) yield Object.assign(async () => "baz", { task: 2}) })
关键说明
- 泛型调整:将原函数的泛型
<T, J extends Job<T>>改为<J extends Job<any>>,让TypeScript优先推断J的类型,避免T的推断阻塞。 - 类型提取:使用
J extends Job<infer T> ? T : never从J中提取异步函数的返回类型T,确保JobSettlement中的T与J的实际返回值类型一致。 - 类型断言:在
yield时添加类型断言,帮助TypeScript明确识别产出值的具体类型(否则可能因为联合类型的歧义导致推断不准确)。
这样修改后,settlementSequence的类型会被正确推断为AsyncIterable<JobSettlement<string, () => Promise<string>>>,带元数据的settlementSequenceWithMetadata也能正确保留元数据类型,同时T被推断为string。
内容的提问来源于stack exchange,提问作者cefn
相关产品推荐
相关产品推荐

