Menu
flag Ar iconالعربيةdown icon

typeof في TypeScript: Type Guards وعامل الأنواع typeof

للعامل typeof وظيفتان في TypeScript. في الكود هو عامل JavaScript الذي يعيد "string" و"number" و"object" وغيرها وقت التشغيل، وتضيّق TypeScript الأنواع بناءً عليه. وفي الأنواع هو استعلام نوع ينسخ نوع متغير، كما في keyof typeof obj وReturnType<typeof fn>.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

لـ typeof معنيان في TypeScript. في التعبير هو عامل JavaScript: يُنفذ ويعيد نصًا مثل "string" أو "number"، وتضيّق TypeScript المتغير عندما تقارن ذلك النص. وفي موضع نوع هو استعلام نوع: typeof config يعطي النوع الثابت للمتغير config.

يُظهر السطر الأخير الفرق: typeof custom داخل console.log هو العامل وقت التشغيل ويطبع object، بينما typeof defaults بعد type Options = هو الاستعلام وقت الترجمة ولا يصل أبدًا إلى JavaScript.

المعنيان في لمحة

typeof وقت التشغيل (JavaScript)استعلام النوع typeof (TypeScript)
أين يظهرأي تعبير: if وreturn وconsole.log(...)مواضع الأنواع: بعد :، وفي type X = ...، وداخل <...>
مثالtypeof x === "string"let y: typeof x;
متى يُقيَّمعند تشغيل الكودبواسطة المترجم، ثم يُمحى
الناتجأحد ثمانية نصوصنوع
يُستخدم لـفحص قيمة وتضييق نوعهااشتقاق نوع من قيمة

تميّز TypeScript بينهما بالموضع، فلا تعني الكلمة نفسها الاثنين في آن واحد.

نتائج typeof وقت التشغيل

يعيد العامل وقت التشغيل أحد ثمانية نصوص. شغّل هذا لترى ما تعطيه القيم الشائعة:

القيمةناتج typeofملاحظة
"hi" وقوالب النصوص"string"
42 و3.14 وNaN وInfinity"number"NaN رقم؛ افحصه بـ Number.isNaN
10n"bigint"
true وfalse"boolean"
undefined"undefined"
Symbol("id")"symbol"
الدوال والدوال السهمية والأصناف"function"الصنف دالة مُنشئة
null"object"خطأ تاريخي في JavaScript
{} و[] وnew Date() وnew Map()"object"المصفوفات كائنات: استخدم Array.isArray
new String("x") وnew Number(1)"object"كائنات مغلِّفة، تجنبها

في JavaScript العادية يعيد typeof على متغير لم يُعلن قط القيمة "undefined" بدل رمي خطأ. أما في TypeScript فلا يُترجم هذا الكود: Cannot find name 'notDeclared'. (TS2304).

التضييق باستخدام typeof

مقارنة typeof في if أو switch أو تعبير ثلاثي أو بعد && تضيّق المتغير في كل فرع. إنها الطريقة المعيارية لمعالجة union من الأنواع البدائية، وأول فحص تلجأ إليه مع unknown.

يضيّق typeof x !== "string" في الاتجاه الآخر، إلى كل شيء ما عدا string. ويعرف المترجم النصوص الثمانية الممكنة، فيكون الخطأ الإملائي في المقارنة خطأ ترجمة لا فحصًا يكون خاطئًا دائمًا بصمت:

يطبع المترجم index.ts(3,7): error TS2367: This comparison appears to be unintentional because the types '"bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined"' and '"strnig"' have no overlap. في JavaScript العادية كان الخطأ الإملائي سيرسل كل نص بهدوء إلى مسار number. صحح الإملاء فيطبع text.

فخ typeof null

لأن typeof null يساوي "object"، تضيّق TypeScript الفحص typeof x === "object" إلى object | null لا إلى object. أضف فحص null، وإلا تكون قراءة الخاصية خطأ (TS18047 'x' is possibly 'null'.).

لا يستطيع typeof التمييز بين المصفوفات والتواريخ والخرائط والكائنات العادية: كلها "object". استخدم Array.isArray(x) للمصفوفات وx instanceof Date لنسخ الأصناف. ولا يستطيع typeof ولا غيره التحقق وقت التشغيل من أن قيمة تطابق interface، لأن الواجهات تُمحى؛ لذلك اكتب دالة type guard تفحص الخصائص.

typeof في مواضع الأنواع

في النوع، ينسخ typeof someVariable النوع الذي استنتجته TypeScript (أو أعلنته أنت) لذلك المتغير. يوفر عليك كتابة نوع يدويًا لقيمة موجودة أصلًا، ويبقي الاثنين متزامنين.

const theme = {
  primary: "#3178c6",
  spacing: 8,
  dark: false,
};

type Theme = typeof theme;
// { primary: string; spacing: number; dark: boolean }

function withSpacing(t: Theme, factor: number): Theme {
  return { ...t, spacing: t.spacing * factor };
}

console.log(withSpacing(theme, 2)); // { primary: '#3178c6', spacing: 16, dark: false }

let userName = "Ada";
const fixed = "Ada";
type A = typeof userName; // string
type B = typeof fixed;    // "Ada" (a const keeps its literal type)

يعتمد الناتج على طريقة تعريف المتغير: let أو خاصية الكائن يتوسعان (string وnumber)، والقيمة البدائية المعلنة بـ const تحتفظ بنوعها الحرفي. أضف as const إلى كائن أو مصفوفة فيعطي typeof أنواعًا حرفية للقراءة فقط حتى أعمق مستوى. ويقبل typeof أيضًا الوصول إلى الخصائص، فـ typeof theme.spacing هو number، لكنه لا يقبل تعبيرات عشوائية: type T = typeof getTheme(); خطأ صياغة (';' expected.، TS1005). وللنوع الذي يعيده استدعاء، استخدم ReturnType<typeof getTheme>.

keyof typeof: مفاتيح كائن كنوع

keyof typeof obj هو التركيب الأكثر شيوعًا. يحوّل typeof الكائن إلى نوع، ويأخذ keyof مفاتيحه، فتحصل على union من أسماء الخصائص يبقى صحيحًا كلما تغيّر الكائن.

والحيلة نفسها على مصفوفة ثابتة تعطي union من قيمها: مع const roles = ["admin", "editor"] as const يكون النوع (typeof roles)[number] هو "admin" | "editor". ودون as const سيكون مجرد string. وتغطي صفحة keyof العامل keyof وحده.

ReturnType<typeof fn> وtypeof على الأصناف

تأخذ أنواع الأدوات مثل ReturnType وParameters نوع دالة. واسم الدالة قيمة، فمرّره عبر typeof أولًا:

كتابة ReturnType<createUser> تفشل بـ 'createUser' refers to a value, but is being used as a type here. Did you mean 'typeof createUser'? (TS2749)، وهذا المترجم يطلب بالضبط ما سبق.

الأصناف هي الحالة الوحيدة التي يكون فيها الاسم قيمة ونوعًا معًا. User كنوع يعني نسخة من الصنف؛ وtypeof User يعني الصنف نفسه، أي المُنشئ، بما في ذلك أعضاؤه الثابتة:

class Point {
  static origin = new Point(0, 0);
  constructor(public x: number, public y: number) {}
}

const p: Point = new Point(1, 2);        // an instance
const Ctor: typeof Point = Point;        // the class (constructor + statics)
const q = new Ctor(3, 4);                // q: Point
type Instance = InstanceType<typeof Point>; // Point

typeof مقابل instanceof مقابل type guard

الفحصيعمل معمثال
typeofالأنواع البدائية، والدوال، و«هل هو كائن»typeof x === "number"
Array.isArrayالمصفوفاتArray.isArray(x)
instanceofنسخ الأصناف (Date وError وأصنافك)x instanceof Date
inunions الكائنات، بحسب الخاصية"email" in x
دالة type guardالواجهات وtype aliases وأي شيء آخرisUser(x) مع x is User

اختر أضيق أداة مناسبة. لنسخ الأصناف انظر instanceof؛ وللأشكال التي يصفها interface، تكون دالة type guard هي الفحص الوحيد المتاح وقت التشغيل.

الأسئلة الشائعة

ماذا يفعل typeof في TypeScript؟

شيئين مختلفين بحسب موضعه. في التعبير، typeof x هو عامل JavaScript: يُنفذ ويعيد نصًا مثل "string" أو "object"، وتضيّق TypeScript نوع x عندما تقارن ذلك النص. وفي تعليق نوع، typeof x استعلام نوع: يقيّمه المترجم ويعطي النوع الثابت للمتغير x، ويختفي من كود JavaScript الناتج.

ما هو keyof typeof في TypeScript؟

يعطي keyof typeof obj الـ union من أسماء خصائص كائن كأنواع نصية حرفية. يحوّل typeof obj قيمة الكائن إلى نوعها، ويأخذ keyof مفاتيح ذلك النوع. لـ const colors = { red: "#f00", blue: "#00f" } يكون keyof typeof colors هو "red" | "blue".

لماذا يعيد typeof null القيمة "object"؟

إنه خطأ من أول إصدار من JavaScript لم يعد ممكنًا إصلاحه دون كسر الويب. تنمذجه TypeScript: بعد typeof x === "object" يُضيَّق x إلى object | null، فيجب أن تفحص x !== null أيضًا قبل قراءة الخصائص.

كيف أتحقق من أن قيمة مصفوفة في TypeScript؟

استخدم Array.isArray(value)، الذي يضيّق إلى نوع مصفوفة. لا يستطيع typeof فعل ذلك: typeof [] يساوي "object"، كما في الكائنات العادية وnull.

ما الفرق بين typeof و instanceof في TypeScript؟

يفحص typeof الفئة البدائية للقيمة ("string" و"number" و"function" و"object"...). أما instanceof فيفحص ما إذا كان كائن قد أُنشئ بصنف أو مُنشئ معين، مثل Date أو class User الخاص بك. استخدم typeof للأنواع البدائية وinstanceof لنسخ الأصناف؛ ولا يستطيع أي منهما فحص interface أو type alias، فهما غير موجودين وقت التشغيل.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن