أنواع مفاهيم TypeScript — الأنواع المهمة للحفظ (والمتبقي)

تحديث في

جزئي، اختيار، تجاهل، تسجيل، نوع العودة، المعلمة، مُنتظر — ثمانية أنواع مفيدة مع أمثلة قبل وبعد وتحليل صريح حول أي من هذه الأنواع ستستخدمها كل أسبوع.

TypeScript Utility Types — The Ones Worth Memorizing (and the Rest) 1
إعلان · حذف؟

ربما قرأت صفحة مرجعية لـ TypeScript تُعرض 20+ نوعًا مفيدًا بترتيب أبجدي، وتُعرّف كل نوع بجملة، مما جعلك تسأل عن أي من هذه الأنواع يجب أن تُدمجها في تطبيقاتك، ومتى تُستخدم، ومتى تُستخدم فقط في تطوير مكونات الإطار. هذه النسخة الأكثر صدقًا: ثمانية أنواع، أمثلة محددة قبل وبعد، ورد واضح حول الاستخدام اليومي مقابل الاستخدام النادر.

إذا بدأت من JSON الخام ولم تكتب واجهاتك بعد، فإن مُحول JSON إلى TypeScript سيُسهم في إنشاء واجهة أساسية خلال ثوانٍ — ثم عد إلى هنا لطبقة هذه الأنواع المفيدة.

Partial — استخدام أسبوعي. تعلّمها أولاً.

تُجعل كل خاصية في T اختيارية. الاستخدام القياسي هو التحديثات من نوع PATCH، حيث تُرسل فقط الحقول التي تغيرت.

// Before: manually duplicating the interface with optional versions of everything
interface UserUpdate {
  name?: string;
  email?: string;
  age?: number;
}

// After: Partial derives it from the source of truth
interface User {
  name: string;
  email: string;
  age: number;
}

function updateUser(id: string, updates: Partial<User>) {
  // updates.name is string | undefined — TypeScript knows
}

المشكلة في النسخة "قبل": إذا أضفت حقلًا إلى User، يجب أن تذكّر أن تُضاف إلى UserUpdate كما. Partial<User>باستخدام

، فإن إضافة حقل إلى واجهة المصدر تجعله متاحًا تلقائيًا في التحديثات. تبقى الأنواع متزامنة.

Required — استخدام شهري، لكنه يُوفر لك في موقف محدد. Partial المقابل لـ ? — يُزيل كل

// Before: after validating, you still fight undefined checks everywhere
interface Config {
  apiUrl?: string;
  timeout?: number;
  retries?: number;
}

function initApp(config: Config) {
  config.apiUrl?.trim(); // need optional chaining even after checking
}

// After: Required signals "this has been validated, stop warning me"
function validateAndInit(raw: Config): void {
  if (!raw.apiUrl) throw new Error("apiUrl required");
  if (!raw.timeout) throw new Error("timeout required");
  if (!raw.retries) throw new Error("retries required");

  const config = raw as Required<Config>;
  config.apiUrl.trim(); // no optional chaining needed
}

من نوع معين. أكثر فائدة بعد التحقق من القيم: تُستلم مُدخلات مُعدّة بشكل غير دقيق، وتُتحقق من وجود جميع الحقول، ثم ترغب أن يُوقف TypeScript عن التساؤل حول إمكانية أن تكون كل شيء غير مُحدد. Required<T> ملاحظة صادقة:

لا تُحقق التحقق في الزمن الحقيقي — لا يزال عليك كتابة التحقق. فقط يُغيّر ما يعتقد عنه TypeScript في المراحل اللاحقة. استخدمه لنقل "هذا تم التحقق منه" على مستوى الأنواع.

Pick — استخدام أسبوعي. اختر ما تريده. Tتُنشئ نوعًا جديدًا يحتوي فقط على الخصائص التي تُحدّدها من

// Before: manually maintaining a separate interface that drifts from User
interface UserPublicProfile {
  name: string;
  bio: string;
  avatarUrl: string;
}

// After: Pick stays in sync with the source
interface User {
  id: string;
  name: string;
  email: string;       // private — shouldn't go to clients
  passwordHash: string;  // definitely private
  bio: string;
  avatarUrl: string;
}

type UserPublicProfile = Pick<User, "name" | "bio" | "avatarUrl">;

. مفيد عندما ترغب في جزء من واجهة أكبر — أشكال واجهة عامة، نماذج عرض، أو الاستجابات المُسلّمة. Pick هو الأداة المناسبة عندما يكون عدد الخصائص التي ترغب في أقل من عدد الخصائص التي تحتاج إلى exclude. عندما يصبح الاتجاه عكسيًا، ابحث عن Omit.

Omit — استخدام أسبوعي. اختر ما لا ترغب فيه.

مكمل لـ Pick — يُنشئ نوعًا يحتوي على جميع خصائص T إلا الخصائص التي تُحدّدها. عندما يكون لديك واجهة كبيرة وعدد قليل من الحقول التي تُستبعد، فإن Omit يجعل المقصود أكثر وضوحًا مقارنة بكتابة كل ما ترغب فيه.

// Before: manually listing every field except the sensitive ones
// Easy to miss a new field added to User later
interface UserForClient {
  id: string;
  name: string;
  email: string;
  bio: string;
  avatarUrl: string;
  // passwordHash intentionally omitted — but a future dev might not know that
}

// After: Omit states the exclusion explicitly
type UserForClient = Omit<User, "passwordHash">;
// If User gains a new "address" field, UserForClient gets it automatically

شيء لا يفعله أي من Pick أو Omit: تغيير نوع الخصائص الفردية. إذا كنت ترغب في اختيار حقول و وإعادة تشكيل أنواعها، فأنت تبحث عن نوع مُمَدّد، وهو أداة مختلفة تمامًا.

Record — استخدام أسبوعي. المُكتبة المُصنّفة.

تُنشئ نوعًا لجسم يحتوي على جميع المفاتيح من نوع K وكل القيم من نوع V. الفائدة الحقيقية تظهر عندما يكون K نوعًا متعددًا — سيُظهر TypeScript خطأ إذا كنت تفتقر إلى مفتاح. الأشكال العامة المُستقبلية تقبل المُدخلات غير المكتملة بشكل سكين؛ أما Record مع مفتاح متعدد فإنها لا تقبل ذلك.

// Before: index signature with no exhaustiveness checking
const rolePermissions: { [key: string]: string[] } = {
  admin: ["read", "write", "delete"],
  editor: ["read", "write"],
  // forgot "viewer" — TypeScript doesn't notice
};

// After: Record with a union key enforces completeness
type Role = "admin" | "editor" | "viewer";

const rolePermissions: Record<Role, string[]> = {
  admin: ["read", "write", "delete"],
  editor: ["read", "write"],
  viewer: ["read"],
  // TypeScript error if any Role is missing
  // TypeScript error if you try to add an unknown key
};

التحقق من التكامل هو الفائدة الحقيقية. تُصبح مهمة عندما يمثل المفاتيح شيئًا معنويًا مثل الأدوار، أنواع الأحداث، طرق HTTP، أو أكواد الحالة — أي شيء حيث أن غياب حالة يُعدّ خطأ، وليس مجرد تجاهل.

ReturnType — استخدام أسبوعي إذا كنت تستخدم دوال من مكتبات خارجية.

تُستخرج نوع الإرجاع من دالة. أكثر فائدة عندما تستخدم دالة من مكتبة وتريد أن تُحدد نوع متغير يحتوي على الناتج — دون الحاجة إلى استيراد نوع الإرجاع بشكل منفصل (وهي لا تُصدر دائمًا بشكل نظيف).

// Before: manually annotating the return type — it can drift
function getCurrentUser() {
  return { id: "u1", name: "Alice", roles: ["admin"] as const };
}

let cachedUser: { id: string; name: string; roles: readonly string[] };
// If getCurrentUser's return changes, this annotation doesn't update automatically

// After: ReturnType derives it and keeps in sync
type CurrentUser = ReturnType<typeof getCurrentUser>;
let cachedUser: CurrentUser;

// Especially useful with unexported library types:
import { useQuery } from "@tanstack/react-query";
type QueryResult = ReturnType<typeof useQuery>;
// No need to figure out what QueryObserverResult<...> looks like or import it

Parameters — استخدام نادر. غالبًا ما تُستخدم في الوسائط.

تُستخرج أنواع المدخلات من الدالة كمُتسلسل. الملاحظة الصادقة: لن تستخدم هذا أسبوعيًا إلا إذا كتبت الكثير من الوسائط أو الأدوات المُدمجة. لكن عندما تحتاجه، لا توجد بديلة نظيفة.

// Before: manually duplicating parameter types in the wrapper
function createEvent(
  type: string,
  payload: Record<string, unknown>,
  timestamp: number
) { /* ... */ }

// Every time createEvent changes, this wrapper needs a manual update:
function loggedCreateEvent(
  type: string,
  payload: Record<string, unknown>,
  timestamp: number
) {
  console.log("Creating event:", type);
  return createEvent(type, payload, timestamp);
}

// After: Parameters keeps the wrapper in sync automatically
function loggedCreateEvent(...args: Parameters<typeof createEvent>) {
  console.log("Creating event:", args[0]);
  return createEvent(...args);
}

نمط التوزيع + الباقي (...args: Parameters<F>) هو النمط الرئيسي. يظهر أيضًا في مocks الاختبارات: jest.fn<ReturnType<F>, Parameters<F>>() يُعطي لك مُocks مُصنّفًا تمامًا دون الحاجة إلى استيراد توقيع الدالة بشكل منفصل.

Awaited — استخدمه عندما تحتاج إلى تفكيك أنواع الـ Promise دون استدعاء الدالة.

تم إضافته في TypeScript 4.5 (تم الإصدار في نوفمبر 2021). يُفكّك تدريجيًا Promise<T> لإيجاد T. قبل وجوده، كان الحصول على نوع الناتج من دالة أсинحنة يتطلب كتابة نوع شرطي: ReturnType<F> extends Promise<infer U> ? U : never — والذي ينهار عند التغليف المزدوج للـ Promise ويكون غير مريح للقراءة في التغييرات.

// Before: conditional type to unwrap — breaks on nested Promises
async function fetchUser(id: string) {
  const res = await fetch(`/api/users/${id}`);
  return res.json() as { id: string; name: string; email: string };
}

type FetchedUser =
  ReturnType<typeof fetchUser> extends Promise<infer U> ? U : never;
// Works for Promise<T> but not Promise<Promise<T>>

// After: Awaited handles both cases cleanly
type FetchedUser = Awaited<ReturnType<typeof fetchUser>>;

// Awaited recursively unwraps:
type A = Awaited<Promise<string>>;            // string
type B = Awaited<Promise<Promise<string>>>;  // string
type C = Awaited<string>;                      // string (no-op on non-Promise)

التركيب Awaited<ReturnType<typeof fn>> مهم أن تُحفظ كوحدة واحدة — يغطي 90% من استخراج أنواع الأنشطة في كود التطبيق.

مذكرة سريعة

نوع مفيدما تفعلهمعدل الاستخدامالاستخدام الرئيسي
Partial<T>تُصبح جميع الخصائص اختياريةأسبوعيمُدخلات التحديث من نوع PATCH
Required<T>تُصبح جميع الخصائص الاختيارية مطلوبةشهرياإشارات "تم التحقق من الانتهاء" بعد التحقق من القيم
Pick<T, K>يحتفظ فقط بالخصائص المحددةأسبوعيأشكال واجهة عامة، نماذج عرض
Omit<T, K>يُزيل الخصائص المحددةأسبوعيإزالة الحقول الحساسة أو غير الضرورية
Record<K, V>جسم يحتوي على مفاتيح من نوع K وقيم من نوع Vأسبوعيمُكتبات مُصنّفة مع تحقق من التكامل
ReturnType<F>تُستخرج نوع الإرجاع من الدالةأسبوعي (خاصة مع المكتبات)تحديد متغير من نوع مُستمِد أو غير مُستورد من نوع الإرجاع
Parameters<F>تُستخرج أنواع المدخلات من الدالة كمُتسلسلنادرالوظائف المُدمجة، المocks المُصنّفة
Awaited<T>يُفكّك أنواع الـ Promise تدريجيًانادرالحصول على نوع الناتج من الدوال الأсинحنة

الأنواع غير المذكورة في هذه القائمة

يأتي أيضًا مع TypeScript Readonly<T>, NonNullable<T>, Extract<T,U>, Exclude<T,U>, InstanceType<C>, ConstructorParameters<C>، وعدد من أنواع التعبيرات المُبنية. فهي حقيقية وفريدة في بعض الأحيان، لكنها تظهر في كود المكتبات، الأدوات العامة، والبرمجة على مستوى الأنواع — وليس في منطق التطبيقات العادية. إذا تعلمت الثمانية المذكورة أعلاه، فابقَ على استعداد لاستكشاف الباقي عندما تحتاجه حقًا.

المبدأ الأساسي هو نفسه في جميعها: وصف تحويل لشكل موجود بدلاً من تكراره. أسماء الأنواع المفيدة هي مجرد مفردات تُعبّر عن هذا الهدف لـ TypeScript.

هل تريد حذف الإعلانات؟ تخلص من الإعلانات اليوم

تثبيت ملحقاتنا

أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع

أضف لـ إضافة كروم أضف لـ امتداد الحافة أضف لـ إضافة فايرفوكس أضف لـ ملحق الأوبرا

وصلت لوحة النتائج!

لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!

إعلان · حذف؟
إعلان · حذف؟
إعلان · حذف؟

ركن الأخبار مع أبرز التقنيات

شارك

ساعدنا على الاستمرار في تقديم أدوات مجانية قيمة

اشتري لي قهوة
إعلان · حذف؟