在 TypeScript 中,Promise 是处理异步操作的核心机制。相比于 JavaScript,TypeScript 中的 Promise 最大的优势在于类型安全(Type Safety),它能让你明确知道异步操作返回的数据类型。
以下是关于 TypeScript 中 Promise 的详细介绍,从基础定义到高级用法。
1. 核心概念与泛型 (Promise<T>)
在 TypeScript 中,Promise 是一个泛型接口,定义为 Promise<T>。
T: 代表 Promise 成功(Resolved) 时返回的数据类型。- 如果 Promise 不返回任何值(只处理过程),通常使用
Promise<void>。
基本语法示例
typescript
// 显式声明返回类型为 string
const myPromise: Promise<string> = new Promise((resolve, reject) => {
console.log("异步执行")
const success = true; //--------->New的时候 这块代码就被执行
if (success) {
resolve("操作成功!"); // 这里的参数必须是 string
} else {
reject(new Error("操作失败"));
}
});
console.log("主程序执行1")
myPromise.then((data) => { //--------->拿到执行结果
console.log(data.length); // TS 知道 data 是 string,所以允许访问 .length
});
console.log("主程序执行2")
运行输出结果
typescript
[LOG]: "异步执行"
[LOG]: "主程序执行1"
[LOG]: "主程序执行2"
[LOG]: 5
2. 创建 Promise 的方式
2.1 使用构造函数 (new Promise)
这是最基础的写法,构造函数接受一个执行器函数 (resolve, reject) => void。
typescript
function fetchUser(id: number): Promise<{ id: number; name: string }> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
// resolve 的参数必须符合 Promise<{...}> 中定义的结构
resolve({ id, name: "Alice" });
} else {
reject("ID 无效");
}
}, 1000);
});
}
2.2 使用 async 和 await (推荐)
这是现代开发的标准写法。async 函数的返回值永远是一个 Promise 。TS 会根据 return 的值自动推断 Promise 的泛型类型。
typescript
// 写法 1: 自动推断
async function getUser() {
return "Alice"; // TS 推断返回类型为 Promise<string>
}
// 写法 2: 显式注解 (推荐,更规范)
async function getScore(): Promise<number> {
return 100;
}
// 使用 await
async function main() {
const score = await getScore(); // score 被推断为 number 类型
console.log(score);
}
3. Promise 的状态与回调
Promise 有三种状态:pending (进行中), fulfilled (已成功), rejected (已失败)。
在 TS 中,.then() 链式调用时,类型会自动流转。
typescript
const p = Promise.resolve(10); // 类型: Promise<number>
p.then((num) => {
// num 是 number
return num.toString(); // 返回 string
})
.then((str) => {
// str 是 string (TS 自动推断)
console.log(str);
return true; // 返回 boolean
})
.then((bool) => {
// bool 是 boolean
});
4. 静态方法 (Static Methods)
TypeScript 对 Promise 的静态方法也有很好的类型支持。
4.1 Promise.resolve<T>(value: T)
创建一个立即成功的 Promise。
typescript
const p1 = Promise.resolve(42); // Promise<number>
const p2 = Promise.resolve({ name: "Bob" }); // Promise<{ name: string }>
4.2 Promise.reject(reason: any)
创建一个立即失败的 Promise。
typescript
const pFail = Promise.reject("Error occurred"); // Promise<never>
4.3 Promise.all<T[]>(values: [])
等待所有 Promise 完成。返回值的类型是一个元组(Tuple)或数组。
typescript
const pString = Promise.resolve("Hello");
const pNumber = Promise.resolve(123);
// TS 能够推断出 results 的类型是 [string, number]
Promise.all([pString, pNumber]).then(([str, num]) => {
console.log(str.toUpperCase()); // 正常
console.log(num.toFixed(2)); // 正常
});
4.4 Promise.allSettled<T>(...)
等待所有 Promise 完成(无论成功或失败)。
typescript
const p1 = Promise.resolve(10);
const p2 = Promise.reject("error");
Promise.allSettled([p1, p2]).then((results) => {
results.forEach((result) => {
if (result.status === 'fulfilled') {
console.log(result.value); // TS 知道这里有 value
} else {
console.log(result.reason); // TS 知道这里有 reason
}
});
});
4.5 Promise.race<T>(...)
返回第一个改变状态(成功或失败)的 Promise 的结果。
5. 常见实战场景
5.1 定义 API 响应接口
这是前端开发中最常用的模式。
typescript
// 1. 定义数据接口
interface User {
id: number;
name: string;
email: string;
}
interface ApiResponse<T> {
code: number;
data: T;
message: string;
}
// 2. 模拟请求函数
function request<T>(url: string): Promise<ApiResponse<T>> {
return new Promise((resolve) => {
// 模拟网络请求
setTimeout(() => {
resolve({
code: 200,
data: {} as T, // 这里只是为了演示,实际会有真实数据
message: "success"
});
}, 500);
});
}
// 3. 使用
async function fetchUserProfile() {
// 明确告诉 request 返回的数据结构是 User
const response = await request<User>('/api/user/1');
if (response.code === 200) {
// TS 这里会有自动提示:response.data.email
console.log(response.data.email);
}
}
5.2 Promise<void> 用于不返回值的异步操作
例如:初始化数据库、发送日志、等待几秒钟。
typescript
function delay(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms); // 不需要传递参数给 resolve
});
}
async function run() {
console.log("Start");
await delay(1000);
console.log("End after 1s");
}
6. 错误处理 (Error Handling)
在 TypeScript 中处理 Promise 错误时,有一个常见的痛点:catch 中的 error 类型通常是 any 或 unknown。
typescript
async function task() {
try {
await someAsyncOperation();
} catch (error) {
// 默认情况下,error 是 unknown 类型 (TS 4.0+) 或 any
// 你不能直接调用 error.message,除非你进行断言或类型收窄
if (error instanceof Error) {
console.error(error.message);
} else {
console.error("Unknown error:", error);
}
}
}
总结
- 类型注解 :始终使用
Promise<Type>来明确异步操作返回的数据结构。 - Async/Await :优先使用
async函数,它让代码看起来像同步代码,且 TS 能自动推断返回类型。 - 泛型工具 :利用
Promise.all等组合工具时,TS 能够很好地处理元组类型推断。 - 错误处理 :注意
catch块中的类型检查,使用instanceof Error是个好习惯。
如果你有具体的代码场景需要分析,可以发给我,我帮你进一步讲解!