如何在 async/await 中正确 reject?TypeScript 解析

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Async/Await 和 reject:为什么这对新手来说是个痛点?

你是否曾经编写过一个 async 函数,等待服务器响应,然后捕获到 UnhandledPromiseRejection?熟悉吗?这是开发者在转向 TypeScript 中的 async/await 时遇到的最常见问题之一。



在 Stack Overflow 上,问题 "How to reject in async/await syntax?" 获得了数千次浏览。这并非没有原因。乍一看,似乎只需返回 Promise.reject() 就能解决问题。但在实际项目中,情况要复杂得多:类型、调用链、错误上下文丢失等。



在本指南中,我们将详细讲解如何在 TypeScript 的 async 函数中正确拒绝 Promise,学习区分 throw 和 return Promise.reject(),并查看来自实际项目的实战示例。



基础:reject 在 async/await 中如何工作

在深入探讨之前,让我们先回顾一下基础知识。TypeScript 中的任何 async 函数都会返回一个 Promise。如果函数内部发生了 throw 或返回了 Promise.reject(),则该 Promise 会进入 rejected 状态。



// async/await 中最简单的 reject 示例
async function fetchUser(id: number): Promise<User> {
    if (id <= 0) {
        throw new Error('无效的用户 ID');
    }
    // ...获取用户的逻辑
}


这里,throw 会自动转换为 reject。但如果我们想返回一个已经拒绝的 Promise 呢?



throw vs return Promise.reject()

在 TypeScript 中,两种方法都有效,但有一些细微差别:



  • throw — 更符合习惯用法。它会停止函数的执行,并将控制权传递给最近的 catch。
  • return Promise.reject() — 显式返回一个拒绝的 Promise。当需要从另一个函数传递错误时很有用。


// throw 和 return Promise.reject() 的区别
async function processOrder(orderId: string): Promise<OrderStatus> {
    // 选项 1:throw
    if (!orderId) {
        throw new Error('需要订单 ID');
    }
    
    // 选项 2:return Promise.reject
    if (orderId.startsWith('test_')) {
        return Promise.reject(new Error('不允许测试订单'));
    }
    
    return { status: 'processing' };
}


重要提示: TypeScript 在使用 return Promise.reject() 时并不总能正确推断类型。如果函数期望返回 Promise<T>,而您返回了 Promise.reject(),可能会出现类型错误。在这种情况下,最好使用 throw。



在 async 函数中 reject 的典型错误

即使是经验丰富的 TypeScript 开发者有时也会犯一些经典错误。以下是前三大错误:



1. 忘记在调用代码中处理 reject

async function main() {
    // 不好:没有 try/catch
    const user = await fetchUser(-1);
    console.log(user); // UnhandledPromiseRejection!
}

// 好的做法:
async function mainSafe() {
    try {
        const user = await fetchUser(-1);
        console.log(user);
    } catch (error) {
        console.error('获取用户失败:', error);
    }
}


2. 错误的错误类型标注

在 TypeScript 中,catch 块默认捕获 unknown 类型。这是正确的,但有时开发者会尝试直接访问 error.message 而不进行检查。



try {
    await riskyOperation();
} catch (error) {
    // 错误:error 是 unknown 类型
    console.log(error.message); // ❌ 类型 'unknown' 上不存在属性 'message'
    
    // 正确做法:
    if (error instanceof Error) {
        console.log(error.message);
    } else {
        console.log                

博客

书籍推荐