TypeScript: تأكيدات الأنواع في TypeScript

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

يُعلم تأكيد النوع المُترجم بأن «أنا أعرف نوع هذه القيمة أفضل منك» — فهو لا يغير نوع القيمة في وقت التشغيل، بل يؤثر فقط على عملية التحقق من النوع في وقت الترجمة.

1. أساسيات تأكيدات الأنواع

(1) صيغتان

TYPESCRIPT
// as Grammar(Recommendations,JSX "Must" must be used in)
let value: any = "hello";
let length1: number = (value as string).length;

// Angle Bracket Syntax(Cannot be in JSX Used in)
let length2: number = (<string>value).length;
📌 توصية: استخدم صيغة as بشكل ثابت. تتعارض صيغة الأقواس مع علامات المكونات في JSX/TSX، لذا فإن as هي الخيار الأكثر شمولية.

(2) الغرض من التأكيدات

التعبيرات من نوع «تضييق» أو «توسيع» — تُخبر TypeScript بأن تعامل القيمة على أنها نوع آخر متوافق:

TYPESCRIPT
// Narrow:From broad types to narrow types(Common)
let value: string | number = "hello";
let str = value as string;       // Tell the compiler"I'm sure this is string"
console.log(str.toUpperCase());  // ✅

// Broadening:From Narrow Types to Wide Types(Less commonly used)
let name = "Charlie" as string;    // "Charlie" Type from literal "Charlie" Generalize to string

(3) لا تؤدي التعريفات إلى تغيير أنواع البيانات في وقت التشغيل

TYPESCRIPT
let value: any = 42;
let str = value as string;       // The compile-time type is string
console.log(typeof str);         // "number" —— At runtime, it is still number!
// console.log(str.toUpperCase()); // Runtime Crash!number None toUpperCase
🔥 المبدأ الأساسي: لا تُجري تأكيدات الأنواع أي تحويلات أثناء وقت التشغيل. فهي مجرد تعليقات توضيحية للأنواع في وقت التحويل البرمجي. وإذا فشل أحد التأكيدات، فسيظل الخطأ يحدث أثناء وقت التشغيل.



2. سيناريوهات التأكيد الشائعة

(1) أنواع عناصر DOM

TYPESCRIPT
// getElementById Back HTMLElement | null
let input = document.getElementById("myInput") as HTMLInputElement;
// After the assertion, you can use it directly. HTMLInputElement Properties of
console.log(input.value);        // ✅
console.log(input.placeholder);  // ✅

// A Safer Way to Write It——Check first null
let inputEl = document.getElementById("myInput");
if (inputEl instanceof HTMLInputElement) {
  console.log(inputEl.value);    // ✅ instanceof narrow,No assertion required
}

(2) أنواع استجابات واجهة برمجة التطبيقات (API)

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

// JSON.parse Back any——Specify the type using an assertion
let response = JSON.parse('{"id":1,"name":"Charlie","email":"xiao@example.com"}') as User;
console.log(response.name);  // ✅ Type: string

// A Safer Way to Write It——Runtime Validation (See Lesson 26)
function isUser(obj: any): obj is User {
  return typeof obj.id === "number"
    && typeof obj.name === "string"
    && typeof obj.email === "string";
}

let data = JSON.parse('...');
if (isUser(data)) {
  console.log(data.name);  // ✅ Type Guard Narrowing,Safer than assertions
}

(3) تجاوز عمليات التحقق غير الضرورية من السمات

TYPESCRIPT
interface Config {
  host: string;
  port: number;
}

// Direct Assignment——Check for Unnecessary Attributes
// let cfg: Config = { host: "localhost", port: 3000, debug: true };  // ❌

// Method 1:Type Assertion Bypass
let cfg = { host: "localhost", port: 3000, debug: true } as Config;  // ✅

// Method 2:Assign a value to the variable first, then pass it(Using Structured Type Compatibility)
let options = { host: "localhost", port: 3000, debug: true };
let cfg2: Config = options;  // ✅ Variable assignments do not perform unnecessary property checks

▶ مثال: التعامل مع التأكيدات للأنواع المركبة

TYPESCRIPT
type SuccessResponse = {
  status: "success";
  data: { id: number; name: string };
};

type ErrorResponse = {
  status: "error";
  error: { code: number; message: string };
};

type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(response: ApiResponse) {
  if (response.status === "success") {
    // Type Narrowing(Recommendations)
    console.log(response.data.name);
  } else {
    // Type Narrowing(Recommendations)
    console.log(response.error.message);
  }

  // Not recommended——Replace Narrowing with Assertions
  // let data = (response as SuccessResponse).data;  // Danger!
}
▶ جرّب الكود

الناتج:

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


3. تأكيدات const

as const جعل TypeScript يستنتج النوع الحرفي الأكثر دقة لقيمة ما + readonly:

(1) الاستخدام الأساسي

TYPESCRIPT
// None as const——widening Inference
let obj = { host: "localhost", port: 3000 };
// Type:{ host: string; port: number }
obj.host = "other";  // ✅ Can be modified

// With as const — exact literals + readonly
let config = { host: "localhost", port: 3000 } as const;
// Type:{ readonly host: "localhost"; readonly port: 3000 }
// config.host = "other";  // ❌ readonly
// config.port = 8080;     // ❌ readonly

(2) as const للمصفوفات

TYPESCRIPT
// Regular Arrays
let arr = [1, 2, 3];
// Type:number[]

// as const Array——become readonly Tuple
let tuple = [1, 2, 3] as const;
// Type:readonly [1, 2, 3]
// tuple[0] = 10;  // ❌ readonly
// tuple.push(4);  // ❌ readonly

(3) الاستخدامات العملية لـ as const — تعريف الثوابت وأنواع الإجراءات

TYPESCRIPT
// Redux Stylistic action Type Definitions
const INCREMENT = "INCREMENT" as const;
const DECREMENT = "DECREMENT" as const;

// None as const → INCREMENT The type is string(Too wide)
// With as const → INCREMENT typee is "INCREMENT"(Exact Literals)

type Action = {
  type: typeof INCREMENT;
  payload: number;
} | {
  type: typeof DECREMENT;
  payload: number;
};

function reducer(state: number, action: Action): number {
  switch (action.type) {
    case "INCREMENT": return state + action.payload;
    case "DECREMENT": return state - action.payload;
  }
}


4. تأكيد عدم الفراغ !

يُعلم التأكيد على عدم الفراغ لغة TypeScript بأن «أنا متأكد من أن هذه القيمة ليست فارغة أو غير محددة»:

(1) الاستخدام الأساسي

TYPESCRIPT
let value: string | null = "hello";

// Non-empty assertion——Tell the compiler"The value is not null"
console.log(value!.toUpperCase());  // ✅ Compilation successful

// Equivalent to asserting that
console.log((value as string).toUpperCase());

(2) السيناريوهات الشائعة

TYPESCRIPT
// DOM Element
let el = document.getElementById("app");
el!.innerHTML = "Hello";  // Use ! to assert non-null

// Assignment After the Optional Chain
let user: { name?: string } = { name: "Charlie" };
let nameLength = user.name!.length;  // Assertion name No undefined

// Function Arguments
function process(value: string | undefined) {
  // We"Know"When called value It can't be... undefined
  console.log(value!.toUpperCase());
}

(3) المخاطر المرتبطة بالتأكيدات غير الفارغة

TYPESCRIPT
let value: string | null = null;

// Compilation successful!But it crashes during runtime——value Actually, it is null
// console.log(value!.toUpperCase());  // Runtime Error:Cannot read property of null

// ✅ A Safer Way to Write It——Check first
if (value !== null) {
  console.log(value.toUpperCase());  // Type Narrowing,Compilation+All operations are safe
}
💡 توصية: يجب أن تكون عمليات التحقق من عدم وجود قيمة فارغة الملاذ الأخير. كلما أمكن، استخدم if لإجراء عمليات الفحص أو ?. للتسلسل الاختياري — فهذه بدائل أكثر أمانًا. لا تستخدم ! إلا عندما تكون متأكدًا بنسبة 100٪ من أن القيمة ليست فارغة، لكن المُجمِّع لا يستطيع استنتاج ذلك.



5. التأكيدات المزدوجة وقيود التأكيد

(1) حدود الادعاءات

لا يسمح TypeScript بالتأكيدات النوعية التي لا علاقة لها بالموضوع على الإطلاق:

TYPESCRIPT
let value: string = "hello";

// ✅ string → string | number(From subtype to supertype,Compatibility)
let wide = value as string | number;

// ✅ string | number → string(From Parent Type to Child Type,May not be safe, but allowed)
let narrow = wide as string;

// ❌ string → number(Completely unrelated,Not allowed)
// let num = value as number;

(2) التأكيد المزدوج (يتجاوز القيود؛ يُنصح بشدة بعدم استخدامه)

TYPESCRIPT
let value: string = "hello";

// Through any Transit——Double Assertion
let num = value as unknown as number;  // Compilation successful!

// But at runtime value It's still string
console.log(typeof num);  // "string"
// num.toFixed(2);         // Runtime Crash!
⚠️ تحذير: تتجاوز التأكيدات المزدوجة (as unknown as T) تمامًا عمليات التحقق من سلامة الأنواع. وهذا يعادل إخبار المُترجم: «لا تهتم، سأتحمل المسؤولية الكاملة» — وهو أمر غير صحيح في 99% من الحالات. إذا وجدت نفسك مضطرًا لاستخدام التأكيدات المزدوجة، فمن المرجح جدًّا أن هناك مشكلة في تصميم الكود الخاص بك، ويجب عليك إعادة النظر في بنية الأنواع.**



6. أفضل الممارسات المتعلقة بالتأكيدات

(1) ترتيب الأولويات

TEXT 📖 للعرض فقط
Type Narrowing(if/typeof/instanceof/in)  → Safest,Use as a priority
Type Guard(Custom is Function)           → Safety,Collapse Complex Types
Non-empty assertion !                          → Use with caution,When it is determined that the value is not empty
as Assertion                             → Use less,When there is a clear reason
as const                            → Recommended for constant definitions
Double Assertion as unknown as T            → Highly not recommended,99%This is incorrect usage.

(2) قائمة مراجعة سلامة التأكيدات

قبل كتابة تأكيد as، اسأل نفسك ثلاثة أسئلة:

  1. هل يمكنني استخدام تضييق النوع بدلاً من ذلك؟ (if/typeof/instanceof)
  2. هل يمكنني التبديل إلى التسلسل الاختياري؟ (?.)
  3. إذا فشل أحد الافتراضات، فهل سيتعطل البرنامج أثناء التشغيل؟

إذا كانت إجابتك على السؤال رقم 3 هي «نعم»، ففكر في اتباع طريقة أكثر أمانًا.

▶ مثال: مقارنة بين التأكيدات الآمنة وغير الآمنة

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

// ❌ Unsafe——Blind assertions API Response
function fetchUser1(id: number): User {
  let data = JSON.parse(localStorage.getItem(`user:${id}`) ?? "{}") as User;
  return data;  // data May not match User Structure
}

// ✅ Safety——Runtime Validation + Type Guard
function isUser(obj: any): obj is User {
  return obj
    && typeof obj.id === "number"
    && typeof obj.name === "string"
    && typeof obj.email === "string";
}

function fetchUser2(id: number): User | null {
  let raw = localStorage.getItem(`user:${id}`);
  if (!raw) return null;

  let data = JSON.parse(raw);
  if (isUser(data)) {
    return data;  // ✅ Type Guard: Return safely after confirmation
  }
  return null;
}
▶ جرّب الكود

الناتج:

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

▶ مثال: صيغة as مقابل صيغة الأقواس الزاوية

الناتج:

TEXT 📖 للعرض فقط
19
19
TYPESCRIPT
let value: unknown = "Hello, TypeScript!";

// as syntax (recommended — works in JSX/TSX)
let len1: number = (value as string).length;

// Angle-bracket syntax (cannot be used in JSX)
let len2: number = (<string>value).length;

console.log(len1);  // 19
console.log(len2);  // 19

// Both produce identical runtime code —
// the choice is purely about JSX compatibility

الناتج:

TEXT 📖 للعرض فقط
19
19


❓ أسئلة شائعة

س ما الفرق بين تأكيد النوع وتحويل النوع؟
ج يؤثر تأكيد النوع فقط على فحص النوع في وقت التحويل البرمجي ولا يغير القيمة في وقت التشغيل — x as string لا يحول x إلى سلسلة. أما تحويل النوع فيغير نوع القيمة في وقت التشغيل — String(42) يحول 42 فعليًّا إلى "42". إن as في TypeScript هو تأكيد، وليس تحويلًا.
س ما الفرق بين as const وreadonly؟
ج readonly تحدد خاصية واحدة على أنها للقراءة فقط. as const يجعل الكائن أو المصفوفة بأكملها — على جميع المستويات — نوعًا حرفيًا باستخدام readonly. const x = { a: 1 } as const أكثر إيجازًا من let x: { readonly a: 1 } ويوفر حماية عميقة للقراءة فقط.
س متى يكون من المناسب استخدام تعبير التأكيد على عدم الفراغ !؟
ج السيناريو الأنسب هو معالجة DOM — عندما تكون متأكدًا من وجود عنصر معين في HTML لكن TypeScript لا يمكنه التحقق من ذلك. document.getElementById("app")!.innerHTML = "Hi" ويكون ذلك مناسبًا عندما تكون بنية الصفحة معروفة. أما في السيناريوهات الأخرى، فاستخدم تعبير if للتحقق بدلاً من ذلك.
س ما هي بعض الاستخدامات المشروعة لـ as unknown as T (التأكيدات المزدوجة)؟
ج قليلة جدًّا. السيناريو المعقول الوحيد هو عندما يتعذر على نظام الأنواع فعليًّا التعبير عن السلوك المقصود (مثل بعض العمليات العامة المعقدة أو عندما تحتوي تعريفات أنواع مكتبات الجهات الخارجية على أخطاء). ومع ذلك، يمكن تجنب 99% من التأكيدات المزدوجة من خلال إعادة تصميم بنية الأنواع.

📖 ملخص

📝 تمارين

  1. المسألة الأساسية (صعوبة ⭐): استخدم as const لتعريف ثابت الاتجاه DIRECTIONS = ["north", "south", "east", "west"] as const، ثم اكتب دالة تقبل معلمة من النوع typeof DIRECTIONS[number] للتحقق من أن أربع قيم فقط للاتجاه هي القيم الصحيحة.
  2. مشكلة متقدمة (درجة الصعوبة ⭐⭐): اكتب دالة querySelector<T extends HTMLElement>(selector: string): T | null تستخدم الدالة document.querySelector(selector) as T | null داخليًّا. ثم أنشئ استدعاءً يحدد موقع العنصر input ويصل إلى الخاصية value باستخدام تأكيد عدم الفراغ. اكتب نسخة أكثر أمانًا تستخدم عبارة if بدلاً من تأكيد عدم الفراغ.
  3. التحدي (الصعوبة: ⭐⭐⭐): قم بتنفيذ دالة للتحقق من النوع أثناء التشغيل validate<T>(schema: Schema, value: unknown): value is T تستخدم كائنات مخطط بسيطة لوصف قواعد التحقق (مثل { name: "string", age: "number" }) وتتحقق أثناء التشغيل مما إذا كانت قيمة unknown متوافقة؛ وفي حالة التوافق، يتم تضييق نطاق حارس النوع إلى T. قارن ذلك بـ as T ووضح أين تكمن الأمان.
Web-Tutorial.com

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

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

100%