TypeScript: أنواع الأدوات المساعدة في TypeScript

آخر تحديث: 2026-08-26

تتضمن لغة TypeScript أكثر من اثني عشر نوعًا من أنواع الأدوات المساعدة — والتي تمثل أفضل الممارسات في البرمجة العامة وتتيح لك إجراء تحويلات الأنواع الشائعة بسطر واحد من التعليمات البرمجية.

1. فئة تحويل الخصائص

(1) جزئي — تصبح جميع الخصائص اختيارية

TYPESCRIPT
interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

// Partial Make all properties optional——Suitable for update operations
type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string; age?: number }

function updateUser(user: User, updates: Partial<User>): User {
  return { ...user, ...updates };
}

let user: User = { id: 1, name: "Charlie", email: "xiao@example.com", age: 20 };
let updated = updateUser(user, { age: 21 });
// Update Only age,All other attributes remain unchanged

console.log(updated.age);   // 21
console.log(updated.name);  // "Charlie"(Unchanged)

(2) إلزامي — أصبحت جميع الخصائص إلزامية الآن

TYPESCRIPT
interface Config {
  host?: string;
  port?: number;
  debug?: boolean;
}

// Required Make all fields required——Suitable for verifying logic
type RequiredConfig = Required<Config>;
// { host: string; port: number; debug: boolean }

function validateConfig(config: RequiredConfig): void {
  console.log(`${config.host}:${config.port} (debug: ${config.debug})`);
}

(3) للقراءة فقط — تصبح جميع الخصائص للقراءة فقط

TYPESCRIPT
interface Point {
  x: number;
  y: number;
}

// Readonly Make all properties read-only
type ReadonlyPoint = Readonly<Point>;
// { readonly x: number; readonly y: number }

let point: ReadonlyPoint = { x: 1, y: 2 };
// point.x = 10;  // ❌ Read-only properties cannot be modified.

// Common Uses:Function Parameter Protection
function freezeConfig(config: Readonly<Config>): void {
  // config.host = "other";  // ❌ Modifications are not allowed.
  console.log("Configuration Frozen");
}

▶ مثال: تحويل أنواع البيانات في عمليات CRUD

TYPESCRIPT
interface Article {
  id: number;
  title: string;
  content: string;
  author: string;
  createdAt: Date;
  updatedAt: Date;
}

// At the time of creation:Not necessary id and timestamps
type CreateArticle = Omit<Article, "id" | "createdAt" | "updatedAt">;

// When updating:All fields are optional
type UpdateArticle = Partial<Omit<Article, "id" | "createdAt">>;

// List View:Show only some fields
type ArticleSummary = Pick<Article, "id" | "title" | "author" | "createdAt">;

// Create
let newArticle: CreateArticle = {
  title: "TypeScriptGetting Started",
  content: "TypeScript is a superset of JavaScript...",
  author: "Charlie"
};

// Update
let updateData: UpdateArticle = {
  title: "TypeScript Advanced",
  content: "An In-Depth Understanding of Generics..."
};

// List
let summary: ArticleSummary = {
  id: 1,
  title: "TypeScriptGetting Started",
  author: "Charlie",
  createdAt: new Date()
};

console.log("Create:" + newArticle.title);
console.log("Update:" + (updateData.title ?? "No changes"));
console.log("Abstract:" + summary.title);
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
Create:TypeScriptGetting Started
Update:TypeScript Advanced
Abstract:TypeScriptGetting Started


2. فصل اختيار السمات

(1) الاختيار — تحديد سمات معينة

TYPESCRIPT
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  role: string;
}

// Pick Select the specified property
type UserPublic = Pick<User, "id" | "name" | "email">;
// { id: number; name: string; email: string }

let publicProfile: UserPublic = {
  id: 1,
  name: "Charlie",
  email: "xiao@example.com"
};
// None password and role —— Safely Disclosing Public Information

(2) حذف — استبعاد سمات معينة

TYPESCRIPT
// Omit Exclude the specified properties(Pick the opposite of)
type UserSafe = Omit<User, "password">;
// { id: number; name: string; email: string; role: string }

let safeUser: UserSafe = {
  id: 1,
  name: "Charlie",
  email: "xiao@example.com",
  role: "admin"
};
// password Excluded

(3) الاختيار مقابل الحذف: الاختيار

TYPESCRIPT
// Retain a few properties → Pick More concise
type Mini = Pick<User, "id" | "name">;           // 2a property → Pick

// Exclude a few attributes → Omit More concise
type NoPassword = Omit<User, "password">;         // Exclusion1 → Omit

// Preserve Most Properties → Omit More concise
type AlmostAll = Omit<User, "password">;          // Retain4 → Omit

// Exclude Most Attributes → Pick More concise
type OnlyTwo = Pick<User, "id" | "name">;         // Exclusion3 → Pick


3. فئات العمليات من النوع «الاتحادي»

(1) استبعاد — استبعاد من نوع الاتحاد

TYPESCRIPT
type AllTypes = "a" | "b" | "c" | "d";

// Exclude Exclude Specified Members
type WithoutA = Exclude<AllTypes, "a">;        // "b" | "c" | "d"
type WithoutAB = Exclude<AllTypes, "a" | "b">; // "c" | "d"

(2) الاستخراج — الاستخراج من نوع الاتحاد

TYPESCRIPT
type Mixed = string | number | boolean | null;

// Extract Extract Specified Members
type OnlyString = Extract<Mixed, string>;       // string
type StringOrNumber = Extract<Mixed, string | number>;  // string | number

(3) NonNullable — استبعاد القيم «فارغ» و«غير معرّف»

TYPESCRIPT
type MaybeString = string | null | undefined;

// NonNullable Exclusion null and undefined
type DefiniteString = NonNullable<MaybeString>;  // string

▶ مثال: تصفية القيم غير الصحيحة

TYPESCRIPT
type EventName = "click" | "focus" | "blur" | null | undefined;

// Exclusion null and undefined
type ValidEvent = NonNullable<EventName>;  // "click" | "focus" | "blur"

// Keep only mouse events
type MouseEvent = Extract<ValidEvent, "click">;  // "click"

// Exclusion click Unforeseen events
type NonClick = Exclude<ValidEvent, "click">;    // "focus" | "blur"

function handleEvent(event: ValidEvent): void {
  console.log(`Handling Events:${event}`);
}

handleEvent("click");   // ✅
handleEvent("focus");   // ✅
// handleEvent(null);   // ❌ NonNullable Ruled out
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
// Executed successfully


4. فئات العمليات من نوع الدالة

(1) ReturnType — الحصول على نوع القيمة المرجعة للدالة

TYPESCRIPT
function createUser(name: string, age: number) {
  return { name, age, active: true };
}

// ReturnType Get the return type——No handwriting required
type User = ReturnType<typeof createUser>;
// { name: string; age: number; active: boolean }

let user: User = { name: "Diana", age: 22, active: false };

(2) المعلمات — استرداد مجموعة من أنواع معلمات الدالة

TYPESCRIPT
function register(name: string, email: string, age: number): void {}

// Parameters Get Parameter Type
type RegisterParams = Parameters<typeof register>;
// [string, string, number]

let params: RegisterParams = ["Charlie", "xiao@example.com", 20];

(3) معلمات المُنشئ — الحصول على أنواع معلمات المُنشئ

TYPESCRIPT
class Point {
  constructor(public x: number, public y: number, public z?: number) {}
}

type PointParams = ConstructorParameters<typeof Point>;
// [number, number, number?]

let args: PointParams = [1, 2];
let point = new Point(...args);

(4) InstanceType — الحصول على نوع مثيل المنشئ

TYPESCRIPT
class Session {
  constructor(public token: string) {}
  isValid(): boolean { return this.token.length > 0; }
}

type SessionInstance = InstanceType<typeof Session>;
// Equivalent to Session Type

let session: SessionInstance = new Session("abc123");


5. السجل — إنشاء نوع زوج المفتاح-القيمة

يُعد Record أحد أنواع البيانات الأكثر استخدامًا — وهو نوع يُستخدم لإنشاء توزيعات «المفتاح-القيمة» بسرعة:

TYPESCRIPT
// Basic Usage:Key and Value Types
type StringMap = Record<string, string>;
let translations: StringMap = {
  hello: "Hello",
  goodbye: "Goodbye"
};

// Coordinated Literal-Union Types——Precision Control Key
type Theme = "light" | "dark";
type ThemeColors = Record<Theme, { bg: string; text: string }>;

let themes: ThemeColors = {
  light: { bg: "#ffffff", text: "#333333" },
  dark: { bg: "#1a1a1a", text: "#e0e0e0" }
};

// Abbreviation: Use Record instead of handwritten Object Types
type Scores = Record<"Chinese Language" | "Mathematics" | "English", number>;
let myScores: Scores = { Chinese Language: 90, Mathematics: 95, English: 88 };


6. كيفية عمل أنواع الأدوات

إن فهم آلية التنفيذ الأساسية لأنواع الأدوات يساعد في تخصيصها:

(1) تنفيذ Partial

TYPESCRIPT
type Partial<T> = {
  [K in keyof T]?: T[K];
};

(2) تنفيذ Readonly

TYPESCRIPT
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

(3) تنفيذ Pick

TYPESCRIPT
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

(4) تنفيذ Omit

TYPESCRIPT
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

(5) تنفيذ Record

TYPESCRIPT
type Record<K extends keyof any, T> = {
  [P in K]: T;
};

▶ مثال: أنواع الأدوات المخصصة

TYPESCRIPT
// DeepPartial——Recursion makes all levels optional
type DeepPartial<T> = {
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};

interface Config {
  server: {
    host: string;
    port: number;
  };
  database: {
    url: string;
    pool: {
      min: number;
      max: number;
    };
  };
}

type PartialConfig = DeepPartial<Config>;
// Properties at all levels are now optional

let config: PartialConfig = {
  server: { host: "localhost" }  // port Can be omitted
  // database The entire section can be omitted.
};

// DeepReadonly——Recursively set all levels to read-only
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

type FrozenConfig = DeepReadonly<Config>;
// config.server.host = "other";  // ❌ Deep Read-Only
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
// Executed successfully


❓ أسئلة شائعة

س ما الفرق بين Partial والخصائص الاختيارية؟
ج يتم تمييز الخصائص الاختيارية يدويًّا بعلامة ? when defining an interface. Partial is a tool type—it automatically makes all properties of an existing type optional. The difference is that Partial is "derived from an existing type" and does not require redefining the interface. In actual development, the UpdateUser = Partial&lt;User&gt;، وتُعد عملية التحديث هذه الحالة الأكثر شيوعًا.
س هل يجب أن أستخدم Pick أم Omit؟
ج يعتمد ذلك على أيهما أكثر إيجازًا — استخدم Pick عندما يكون عدد الخصائص المطلوب الاحتفاظ بها أقل، واستخدم Omit عندما يكون عدد الخصائص المطلوب استبعادها أقل. الاثنان متكاملان؛ اختر الأقصر. قابلية قراءة الكود هي المفتاح — Omit<User, "password"> أوضح بكثير من Pick<User, "id" | "name" | "email" | "role">.
س هل يمكن لـ ReturnType تحديد نوع قيمة الإرجاع لدالة غير متزامنة؟
ج تُرجع الدوال غير المتزامنة Promise؛ بينما تُرجع ReturnType<typeof asyncFn> Promise<T> بدلاً من T. تحتاج إلى فك تغليف Promise باستخدام Awaited<ReturnType<typeof asyncFn>> (يتضمن TypeScript 4.5+ النوع Awaited).
س هل يؤثر نوع الأداة على الأداء؟
ج لا. نوع الأداة هو مجرد عنصر يخص مرحلة الترجمة — حيث يتم مسح جميع معلومات النوع بعد الترجمة، مما يؤدي إلى عدم وجود أي عبء إضافي أثناء وقت التشغيل. ومع ذلك، قد يؤدي التداخل المفرط في الأنواع إلى زيادة وقت الترجمة، وإن كان التأثير الفعلي ضئيلًا للغاية.

📖 ملخص

📝 تمارين

  1. تمرين أساسي (مستوى الصعوبة ⭐): حدد واجهة Todo (id، title، completed، createdAt)، ثم استخدم نوع الأداة لإنشاء: CreateTodo (لا يُشترط إدخال المعرف والوقت عند الإنشاء)، وUpdateTodo (جميع الحقول اختيارية عند التحديث)، وTodoPreview (تعرض العنوان وحالة الإكمال فقط).
  2. تمرين متقدم (درجة الصعوبة ⭐⭐): قم بتخصيص نوع الأداة Mutable<T> — قم بإزالة جميع مُعدِّلات readonly (باستخدام تخطيط المُعدِّلات -readonly). ثم استخدم Readonly<Config> لإنشاء تكوين للقراءة فقط، واستخدم Mutable<Readonly<Config>> للتحقق من استعادة إمكانية الكتابة.
  3. التحدي (الصعوبة: ⭐⭐⭐): قم بتنفيذ نوع الأداة PathKeys<T> — استخراج جميع مسارات الخصائص للكائنات المتداخلة بشكل متكرر. على سبيل المثال، { user: { name: string; address: { city: string } } }"user" | "user.name" | "user.address" | "user.address.city".
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%