在可辨识联合(discriminated union)中使用 async/await 的核心做法是:确保联合类型中的每个分支都返回相同的基础 promise 类型,并在处理函数中通过 switch 语句对标签属性进行匹配,直接 await 各分支的异步操作。这样做能利用 typescript 的类型收窄特性,保证每个分支返回值的类型安全,避免混合不同结构的 promise 导致类型推断失败。

如何定义支持异步操作的联合类型结构
定义联合类型时,必须为每个对象字面量添加唯一的字符串字面量类型作为判别字段(如 type),并确保所有分支的返回值类型统一收敛到同一个 Promise 泛型中。例如,定义一个包含 fetch 和 cache 两种策略的联合类型,两者都必须返回 Promise,这样在后续处理时才能安全地进行类型收窄。

interface FetchStrategy {
type: 'fetch';
url: string;
}
interface CacheStrategy {
type: 'cache';
key: string;
}
type Strategy = FetchStrategy | CacheStrategy;
async function executeStrategy(strategy: Strategy): Promise<string> {
if (strategy.type === 'fetch') {
return await fetch(strategy.url).then(r => r.text());
} else {
return await getCachedData(strategy.key);
}
}</string>
上述代码中,executeStrategy 函数接收一个 Strategy 联合类型。当 strategy.type 被判断为 'fetch' 时,TypeScript 知道此时 strategy 的具体类型为 FetchStrategy,因此可以安全访问 url 属性。同理,在 else 分支中,类型自动收窄为 CacheStrategy,可以访问 key 属性。两个分支最终都返回 Promise,符合函数签名要求。
如何在 switch 语句中正确展开异步逻辑
使用 switch 语句处理联合类型时,需要在每个 case 块内直接执行对应的异步操作并 await 结果。关键在于每个 case 必须明确返回数据,且不能遗漏任何联合类型中的分支,否则 TypeScript 会报错提示非穷尽匹配。同时,要确保每个分支的异步操作完成后返回的数据类型一致。

async function processRequest(strategy: Strategy) {
switch (strategy.type) {
case 'fetch':
const response = await fetch(strategy.url);
if (!response.ok) throw new Error('Network error');
return await response.json();
case 'cache':
const cached = await db.lookup(strategy.key);
if (!cached) throw new Error('Cache miss');
return cached;
default:
const _exhaustiveCheck: never = strategy;
throw new Error('Unknown strategy');
}
}
在 processRequest 函数中,switch 语句根据 strategy.type 的值分发逻辑。在 'fetch' 分支中,先 await HTTP 请求,再 await JSON 解析,最终返回解析后的对象。在 'cache' 分支中,await 数据库查询并返回结果。最后的 default 分支使用了 never 类型检查,如果未来新增联合类型分支而未在此处处理,编译器会报错,从而保证类型的完整性。
当异步操作抛出异常时如何处理类型收窄
在可辨识联合的异步处理中,如果某个分支的异步操作抛出异常,类型收窄依然有效,但需要确保错误处理逻辑覆盖所有分支。通常的做法是在每个 case 内部捕获异常或让异常向上冒泡,同时在函数顶层使用 try/catch 统一处理。由于每个分支返回的是相同的 Promise 类型,异常也会以统一的 Promise 形式传播,不会影响联合类型的结构一致性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











