TypeScript: البرمجة غير المتزامنة والأنواع في TypeScript
آخر تحديث: 2026-08-26
تعد البرمجة غير المتزامنة نمطًا أساسيًا في لغة جافا سكريبت — وتضيف لغة تايب سكريبت دعمًا كاملاً للأنواع في العمليات غير المتزامنة من خلال «Promises» العامة وasync/await.
1. أساسيات نوع Promise
(1) الأنواع العامة للوعود
«A Promise» هو نوع عام — تشير Promise<T> إلى أن «قيمة من النوع T ستُنتج في المستقبل»:
TYPESCRIPT
// Synchronization Functions——Direct Return Value
function getUserSync(): string {
return "Charlie";
}
// Asynchronous Functions——Back Promise<string>
function getUserAsync(): Promise<string> {
return Promise.resolve("Charlie");
}
// Simulate Web Requests
function fetchUser(id: number): Promise<{ id: number; name: string }> {
return new Promise((resolve) => {
setTimeout(() => resolve({ id, name: "User" + id }), 100);
});
}
(2) استدلال الأنواع في then وcatch
TYPESCRIPT
let promise: Promise<string> = Promise.resolve("hello");
promise
.then(value => {
// value Type automatically inferred as string
console.log(value.toUpperCase()); // ✅
return value.length; // Back number → then Chain becomes Promise<number>
})
.then(length => {
// length Type automatically inferred as number
console.log(length.toFixed(2)); // ✅
})
.catch(error => {
// error Type: any(TypeScript Unable to infer the error type)
console.log(error.message);
});
(3) ثبات نوع «Promise» وأمانه
TYPESCRIPT
// Promise It is covariant.——Promise<string> Can be assigned to Promise<string | number>
let p1: Promise<string> = Promise.resolve("hello");
let p2: Promise<string | number> = p1; // ✅ Covariant Safety
// It doesn't work the other way around.
// let p3: Promise<string> = p2; // ❌ Promise<string | number> Cannot be assigned Promise<string>
▶ مثال: عميل واجهة برمجة تطبيقات آمنة من حيث النوع
TYPESCRIPT
interface ApiResponse<T> {
status: number;
data: T;
message: string;
}
interface User {
id: number;
name: string;
email: string;
}
interface Product {
id: number;
title: string;
price: number;
}
function apiGet<T>(url: string): Promise<ApiResponse<T>> {
// Simulation API Call
return new Promise((resolve) => {
setTimeout(() => {
resolve({
status: 200,
data: {} as T, // In actual projects, this is done by JSON.parse Result Assertion
message: "OK"
});
}, 100);
});
}
// Usage——Each request has a specific return type
async function getUser(id: number): Promise<User> {
let response = await apiGet<User>(`/api/users/${id}`);
return response.data;
}
async function getProducts(): Promise<Product[]> {
let response = await apiGet<Product[]>("/api/products");
return response.data;
}
الناتج:
TEXT
📖 للعرض فقط
// Executed successfully
2. الأنواع في غير متزامن/انتظار
(1) قيم الإرجاع للدوال غير المتزامنة
تُرجع الدوال غير المتزامنة دائمًا وعدًا (Promise) — حتى إذا قمت بإرجاع قيمة عادية، فإن TypeScript تقوم تلقائيًا بتغليفها:
TYPESCRIPT
// Explicit Return Values——Automatic packaging is Promise
async function greet(): Promise<string> {
return "Hello"; // Equivalent to return Promise.resolve("Hello")
}
// Explicit Return Promise——No double packaging
async function fetchName(): Promise<string> {
return Promise.resolve("Charlie"); // It won't turn into Promise<Promise<string>>
}
(2) استدلال الأنواع باستخدام await
تنتظر إكمال Promise — نوع await Promise<T> هو T:
TYPESCRIPT
async function example() {
let name: string = await Promise.resolve("Charlie"); // ✅ Unpack to string
let count: number = await Promise.resolve(42); // ✅ Unpack to number
let user: User = await fetchUser(1); // ✅ Unpack to User
}
(3) انتظر «المشكلة» — قد يتم رفض الطلب
TYPESCRIPT
async function riskyOperation(): Promise<number> {
// This Promise possibly reject
let result = await mayFail(); // result The type is number——However, an exception may be thrown during runtime.
return result;
}
async function mayFail(): Promise<number> {
if (Math.random() > 0.5) {
throw new Error("Random failure");
}
return 42;
}
// Safe coding practice — use try/catch
async function safeOperation(): Promise<number | null> {
try {
let result = await mayFail();
return result;
} catch {
return null;
}
}
3. أنواع المرافق من نوع Promise
(1) «Awaited» — كشف النقاب عن نوع «Promise»
يتضمن TypeScript 4.5 النوع Awaited<T> — وهو عبارة عن تفكيك متكرر لـ Promises:
TYPESCRIPT
type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number(Recursive Unpacking)
type C = Awaited<string>; // string (non-Promise, returned directly)
type D = Awaited<Promise<string | number>>; // string | number
(2) الاستخدام العملي — استخراج نوع القيمة المرجعة لدالة غير متزامنة
TYPESCRIPT
async function fetchUser(id: number) {
let response = await fetch(`/api/users/${id}`);
return response.json() as Promise<{ id: number; name: string }>;
}
// Extracting the Return Type of an Asynchronous Function(Remove Promise Packaging)
type UserResponse = Awaited<ReturnType<typeof fetchUser>>;
// { id: number; name: string }
(3) أنواع أدوات المساعدة المخصصة لـ Promise
TYPESCRIPT
// Extract Promise Each element in the array Promise Parsed Type
type UnwrapPromiseArray<T> = {
[K in keyof T]: T[K] extends Promise<infer U> ? U : T[K];
};
type Input = [Promise<string>, Promise<number>, boolean];
type Output = UnwrapPromiseArray<Input>;
// [string, number, boolean]
4. أمان الأنواع في التحكم في التزامن
(1) Promise.all
TYPESCRIPT
async function loadDashboard() {
// Promise.all Accepting different types of Promise Array
let [users, products, stats] = await Promise.all([
fetchUsers(), // Promise<User[]>
fetchProducts(), // Promise<Product[]>
fetchStats() // Promise<Stats>
]);
// Each variable has its own type.
console.log(users.length); // User[].length
console.log(products[0].title); // Product.title
console.log(stats.totalUsers); // Stats.totalUsers
}
(2) Promise.allSettled
TYPESCRIPT
type SettledResult<T> = {
status: "fulfilled";
value: T;
} | {
status: "rejected";
reason: unknown;
};
async function tryMultipleApis() {
let results = await Promise.allSettled([
fetchFromApi1(), // Promise<User>
fetchFromApi2(), // Promise<User>
]);
for (let result of results) {
if (result.status === "fulfilled") {
console.log(result.value.name); // ✅ value Type: User
} else {
console.log(result.reason); // unknown
}
}
}
(3) Promise.race مع Promise.any
TYPESCRIPT
// race——Take the result that was completed first(Whether success or failure)
async function fetchWithTimeout(url: string, ms: number) {
let result = await Promise.race([
fetch(url),
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), ms)
)
]);
return result;
}
// any——Take the first successful result(Ignore Failure)
async function fetchWithFallback() {
let result = await Promise.any([
fetchFromPrimary(), // Priority
fetchFromSecondary(), // Standby
]);
// result Type: All Promise composite types' resolved values
}
▶ مثال: أداة تحميل البيانات المتزامنة
TYPESCRIPT
interface User { id: number; name: string; }
interface Post { id: number; title: string; authorId: number; }
interface Comment { id: number; postId: number; text: string; }
async function fetchAllData(userId: number) {
let [user, posts, comments] = await Promise.all([
fetchUser(userId),
fetchPosts(userId),
fetchComments(userId)
]);
return { user, posts, comments };
}
async function fetchUser(id: number): Promise<User> {
return { id, name: "User" + id };
}
async function fetchPosts(userId: number): Promise<Post[]> {
return [{ id: 1, title: "Article1", authorId: userId }];
}
async function fetchComments(userId: number): Promise<Comment[]> {
return [{ id: 1, postId: 1, text: "Great Article!" }];
}
async function main() {
let data = await fetchAllData(1);
console.log(`User:${data.user.name}`);
console.log(`Number of Articles:${data.posts.length}`);
console.log(`Number of comments:${data.comments.length}`);
}
main();
الناتج:
TEXT
📖 للعرض فقط
// Executed successfully
5. المكررات غير المتزامنة
(1) AsyncIterable مع for انتظار...of
TYPESCRIPT
async function* asyncCounter(max: number): AsyncGenerator<number> {
for (let i = 0; i < max; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
async function run() {
for await (let num of asyncCounter(3)) {
console.log(num);
}
// 0 → 1 → 2(Every interval100ms)
}
(2) أنواع المولدات غير المتزامنة
TYPESCRIPT
interface AsyncGenerator<T> {
next(): Promise<IteratorResult<T>>;
return(value?: any): Promise<IteratorResult<T>>;
throw(e?: any): Promise<IteratorResult<T>>;
[Symbol.asyncIterator](): AsyncGenerator<T>;
}
▶ مثال: نوع الأداة Awaited في الممارسة العملية
TYPESCRIPT
interface User { id: number; name: string; }
interface Post { id: number; title: string; }
async function fetchUser(id: number): Promise<User> {
return { id, name: "User" + id };
}
async function fetchPosts(userId: number): Promise<Post[]> {
return [{ id: 1, title: "Post by " + userId }];
}
type UserType = Awaited<ReturnType<typeof fetchUser>>; // User
type PostsType = Awaited<ReturnType<typeof fetchPosts>>; // Post[]
function render(user: UserType, posts: PostsType): string {
return `${user.name} has ${posts.length} post(s)`;
}
async function main() {
let user = await fetchUser(1);
let posts = await fetchPosts(user.id);
console.log(render(user, posts));
}
الناتج:
TEXT
📖 للعرض فقط
User1 has 1 post(s)
❓ أسئلة شائعة
س هل يجب أن تُرجع الدالة
async قيمة من نوع Promise؟ج يُنصح بتحديد ذلك صراحةً. يمكن لـ TypeScript أن يستنتج أن الدالة
async تُرجع قيمة من نوع Promise، لكن تحديد ذلك صراحةً async function fn(): Promise<T> يوفر مزيدًا من الوضوح — فهو يساعد في التوثيق ويكشف الأخطاء في وقت التحويل البرمجي. يمكنك حذف نوع القيمة المرجعة للدوال البسيطة، لكن يُنصح بتحديده للدوال المعقدة.س لماذا يكون نوع الخطأ «غير معروف» في كتلة catch الخاصة بـ Promise؟
ج نظرًا لأن JavaScript تسمح بإلقاء أي قيمة (ولا تقتصر على Error)، فإن TypeScript لا يمكنها ضمان أن تكون القيمة التي يتم التقاطها من نوع Error. يُنصح بإجراء فحص النوع في كتلة catch:
if (error instanceof Error) أو استخدام تأكيد النوع: error as Error.س ماذا يحدث إذا فشلت إحدى الوعود في
Promise.all؟ج تعمل
Promise.all وفق مبدأ «كل شيء أو لا شيء» — فإذا تم رفض أي وعد واحد، تُرفض عملية all بأكملها. إذا كنت بحاجة إلى «إكمال جميع الوعود (بغض النظر عن النجاح أو الفشل)»، فاستخدم Promise.allSettled. وإذا كنت بحاجة إلى «نجاح أول وعد»، فاستخدم Promise.any.س هل يمكن إعادة تحميل الدوال غير المتزامنة؟
ج نعم. تعمل إعادة تحميل الدوال غير المتزامنة بنفس الطريقة تمامًا كما هو الحال مع الدوال المتزامنة — حيث تصف التوقيعات المعاد تحميلها أنواع القيم المرجعة لمجموعات مختلفة من المعلمات (أغلفة Promise)، ويضمن التنفيذ توافق التوقيعات عبر جميع حالات إعادة التحميل.
📖 ملخص
Promise<T>هو نوع من العمليات غير المتزامنة — حيث يمثل T نوعًا من القيم سيتم إنشاؤه في المستقبل- تُرجع الدوال غير المتزامنة دائمًا وعدًا (Promise)؛
awaitيقوم بفك تغليف الوعد للحصول على T Awaited<T>فك تغليف أنواع الـ«بروميس» بشكل متكرر — استخراج نوع القيمة المرجعة للدوال غير المتزامنة- تقوم دالة Promise.all بتنفيذ عدة وعود (Promises) في وقت واحد وتُرجع مجموعة (تتألف كل عنصر فيها من نوع مختلف)
- تنتظر Promise.allSettled حتى تكتمل جميع الوعود، بينما تأخذ Promise.race أسرعها، وتأخذ Promise.any أول وعود ينجح
- يعمل المولد غير المتزامن
AsyncGenerator<T>معfor await...ofلتنفيذ التكرار غير المتزامن
📝 تمارين
- المشكلة الأساسية (الصعوبة ⭐): اكتب دالة باسم
delay(ms: number): Promise<void>تُرجع وعدًا (Promise) يتم حله بعد ms مللي ثانية. استخدم غير متزامن/انتظار لاستدعاء هذه الدالة وقم بتنفيذ "طباعة رسالة بعد الانتظار لمدة ثانية واحدة". - مشكلة متقدمة (درجة الصعوبة ⭐⭐): اكتب دالة
retry<T>(fn: () => Promise<T>, maxRetries: number): Promise<T>— عندما تفشل الدالة fn، فإنها تعيد المحاولة تلقائيًا حتى عدد المرات المحدد بـ maxRetries. قم بتنفيذ ذلك باستخدام try/catch وحلقة. - مشكلة التحدي (الصعوبة ⭐⭐⭐): قم بتنفيذ
concurrentLimit<T>(tasks: (() => Promise<T>)[], limit: number): Promise<T[]>— قم بتنفيذ المهام بشكل متزامن، على ألا يتجاوز عدد المهام المنفذة في الوقت نفسه الحد الأقصى المحدد. وبمجرد اكتمال جميع المهام، قم بإرجاع مصفوفة من النتائج (بالترتيب نفسه).