TypeScript中Promise.all无法处理联合类型的技术咨询
Let’s break down what’s happening here, and how to fix it without ditching your union type.
The Problem Explained
Your Promisable type is a union of two async functions: one returns Promise<string>, the other Promise<number>. When you call promisable(), TypeScript infers the result as Promise<string> | Promise<number>. Stick that in an array, and you get (Promise<string> | Promise<number>)[].
Here’s the catch: Promise.all expects an iterable of Promises that all resolve to the same (or a unified) type. TypeScript doesn’t automatically convert (Promise<string> | Promise<number>)[] to Iterable<Promise<string | number>>—even though they’re runtime-equivalent, the type system draws a line between "array of either Promise type" and "array of Promises that resolve to a union type". This mismatch is why you get that overload error.
When you remove the union, the array is full of identical Promise<string> values, which fits perfectly with Promise.all’s expected types, so the error goes away.
Fixes That Work With Your Union Type
You don’t have to rewrite your union to () => Promise<string | number>—here are practical alternatives for complex codebases:
1. Explicitly Assert the Array Type
Tell TypeScript to treat the array as Promises resolving to a union type. This is a quick fix that preserves your original union:
type Promisable = (() => Promise<string>) | (() => Promise<number>); const func = async (promisable: Promisable) => { await Promise.all([promisable()] as Array<Promise<string | number>>); };
2. Use Generics for Type Safety
If your use case allows, refactor Promisable to use a generic. This lets TypeScript infer the exact return type of the passed function, keeping things type-safe while playing nice with Promise.all:
type Promisable<T extends string | number> = () => Promise<T>; const func = async <T extends string | number>(promisable: Promisable<T>) => { await Promise.all([promisable()]); };
3. Fall Back to unknown (For Looser Type Checks)
If you don’t need strict type checking for the Promise result, assert the Promise to Promise<unknown>. This bypasses the overload mismatch entirely:
type Promisable = (() => Promise<string>) | (() => Promise<number>); const func = async (promisable: Promisable) => { const promise = promisable() as Promise<unknown>; await Promise.all([promise]); };
Wrap-Up
This isn’t a limitation of Promise.all or union types—it’s just TypeScript being strict about distinguishing between arrays of unioned Promises vs. arrays of Promises resolving to a union. The fixes above let you keep your original union function type without rewriting all your complex async signatures.
内容的提问来源于stack exchange,提问作者dotintegral

