TypeScript异步编程:完整实践指南
现代Web开发离不开异步操作:API请求、数据库操作、文件读取和定时器。TypeScript作为JavaScript的超集,不仅保留了异步编程的所有能力,还通过严格的类型系统使代码更加可预测和安全。在本指南中,我们将深入探讨TypeScript异步编程的关键概念——从基础的Promise到高级模式——并附有真实代码示例。
1. 基础:Promise与类型化
Promise是一个表示异步操作结果的对象,它可以成功完成(fulfilled)或被拒绝(rejected)。TypeScript允许严格类型化Promise返回的值。
// 类型化Promise示例function fetchUserData(userId: number): Promise<{ name: string; email: string }> { return new Promise((resolve, reject) => { setTimeout(() => { if (userId > 0) { resolve({ name: '伊万·伊万诺夫', email: 'ivan@example.com' }); } else { reject(new Error('无效的用户ID')); } }, 1000); });}
// 使用fetchUserData(1) .then(user => console.log(user.name)) // 伊万·伊万诺夫 .catch(error => console.error(error.message));请注意:Promise<{ name: string; email: string }>确保在then中我们得到的对象确实包含这些字段。这避免了与未定义属性相关的错误。
2. Async/Await:TypeScript的语法糖
async和await关键字使异步代码看起来像同步代码,同时不损失性能。TypeScript自动将async函数的返回类型推断为Promise<T>。
// 函数返回 Promise<number>async function getDiscountPrice(price: number, discountPercent: number): Promise<number> { if (discountPercent < 0 || discountPercent > 100) { throw new Error('折扣百分比无效'); } // 模拟异步计算 const discount = await calculateDiscountAsync(price, discountPercent); return price - discount;}
// 辅助函数function calculateDiscountAsync(price: number, percent: number): Promise<number> { return Promise.resolve(price * percent / 100);}
// 使用async function main() { try { const finalPrice = await getDiscountPrice(1000, 20); console.log(`最终价格:${finalPrice}`); // 800 } catch (error) { if (error instanceof Error) { console.error('错误:', error.message); } }}main();重要提示:TypeScript不允许在async函数外部使用await(除非在具有特定设置的模块顶层)。始终将调用包装在async函数中,或使用.then()。
3. 错误处理与高级模式
正确的错误处理是可靠异步代码的基础。TypeScript有助于在编译阶段捕获错误,但处理逻辑仍需手动编写。
3.1. async/await中的错误处理
async function safeFetchData(url: string): Promise<unknown> { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP错误!状态码:${response.status}`); } return await response.json(); } catch (error) { // TypeScript将类型缩小为Error if (error instanceof Error) { console.error('请求错误:', error.message); // 可以返回默认值或继续抛出错误 return null; } throw error; // 未知错误