الوضع الصارم هو الخيار "strict": true في tsconfig.json. إنه مفتاح واحد لثمانية خيارات لفحص الأنواع تكتشف any الضمني، وnull وundefined غير المفحوصين، وإسناد الدوال غير الآمن، وحقول الأصناف غير المهيأة. في TypeScript 7 يكون strict مفعّلًا افتراضيًا. هكذا يبدو الكود الذي يجتازه:
الناتج هو no user وSyntaxError و42. احذف : number أو ?. أو فحص instanceof ولن يُترجم الملف بعدها.
تفعيله
{
"compilerOptions": {
"strict": true
}
}
الخيارات الفردية تتقدم على strict في الاتجاهين. "strict": true, "strictNullChecks": false يُبقي كل شيء عدا فحص null؛ و"strict": false, "noImplicitAny": true يفعّل ذلك الخيار وحده. ويضمّك strict أيضًا إلى الفحوص التي تُضاف في الإصدارات المقبلة، لأن خيارات عائلة strict الجديدة تنضم إلى المجموعة.
لا علاقة لـ strict في TypeScript بالتوجيه "use strict" في JavaScript، وهو وضع وقت تشغيل. يُخرج TypeScript 7 دائمًا "use strict" حيث يلزم، وضبط alwaysStrict: false هو الخطأ TS5108 (أُزيل الخيار).
ما يكتشفه كل خيار
| الخيار | ما يبلّغ عنه | الخطأ |
|---|---|---|
noImplicitAny | معامل أو متغير سيكون نوعه any بصمت | TS7006 Parameter 'x' implicitly has an 'any' type. |
strictNullChecks | استخدام قيمة قد تكون null أو undefined | TS18048 'u' is possibly 'undefined'. |
strictFunctionTypes | إسناد دالة نوع معاملها أضيق من المطلوب | TS2322 |
strictBindCallApply | وسائط خاطئة لـ .call و.bind و.apply | TS2345 |
strictPropertyInitialization | حقل صنف لا يُسند إليه أي قيمة أبدًا | TS2564 Property 'name' has no initializer and is not definitely assigned in the constructor. |
noImplicitThis | this بنوع any ضمني، كما في function متداخلة | TS2683 |
useUnknownInCatchVariables | استخدام متغير catch قبل تضييقه (نوعه unknown) | TS18046 'err' is of type 'unknown'. |
strictBuiltinIteratorReturn | معاملة it.next().value لمكرر مدمج كأنه معرّف دائمًا | TS2322 |
الخياران اللذان يغيّران أكبر قدر من الكود هما noImplicitAny وstrictNullChecks. هذه الكتلة تخالف كليهما عمدًا:
تطبع index.ts(2,17): error TS7006: Parameter 'x' implicitly has an 'any' type. وindex.ts(11,13): error TS18048: 'user' is possibly 'undefined'. دون strict يُترجم هذا الكود ثم ينهار وقت التشغيل مع TypeError: Cannot read properties of undefined (reading 'name'). ومع strict يصبح الانهيار خطأ ترجمة. والإصلاحات هي الكتلة الأولى في هذه الصفحة.
strictFunctionTypes: لماذا يوجد
الدالة التي تتعامل مع النصوص فقط يجب ألا تُستخدم حيث يمكن أن تصل أرقام. الفحص في المثال التالي مُسكت بـ @ts-expect-error حتى تستطيع تشغيله ورؤية ما يمنعه الخطأ:
دون التعليق يكون الإسناد الخطأ TS2322، Type '(s: string) => void' is not assignable to type 'Handler'.، يليه Types of parameters 's' and 'value' are incompatible. يبقى استثناء واحد مقصود: معاملات الدوال المعرّفة بصياغة method (handle(value: string | number): void داخل interface) ما زالت تُفحص بالطريقة الأكثر تساهلًا، لذلك يمكن إسناد shout إلى دالة كهذه دون خطأ.
strictPropertyInitialization
يجب أن يحصل كل حقل في الصنف على قيمة في تعريفه أو في المُنشئ. ثلاث طرق لتحقيق ذلك:
الناتج:
Account {
owner: 'Ada',
balance: 0,
history: [],
lastLogin: undefined,
sessionId: 's-1'
}
الخاصيتان lastLogin وsessionId موجودتان بالقيمة undefined لأن حقول الأصناف حقول JavaScript حقيقية عند target ES2022. تزيل علامة ! الفحص دون أن تضيف أي حماية وقت التشغيل، لذلك فضّل الأشكال الأخرى. يحتاج هذا الخيار إلى strictNullChecks؛ وإيقاف الأخير يعطّله أيضًا.
تفعيل Strict في مشروع قائم
تحويل قاعدة كود كبيرة إلى strict دفعة واحدة قد ينتج مئات الأخطاء. ولأن strict هو الإعداد الافتراضي في TypeScript 7، فترقية مشروع لم يذكر ملف tsconfig.json فيه strict أبدًا تفعّله تلقائيًا؛ اكتب "strict": false إذا احتجت إلى السلوك القديم أثناء النقل. طريق يُبقي البناء ناجحًا:
- أضف
"strict": trueوأوقف الخيارات التي فيها أكثر الأخطاء، وهي عادة"strictNullChecks": falseو"noImplicitAny": false. - أصلح الأخطاء المتبقية، ثم فعّل خيارًا آخر وكرر.
- في
noImplicitAnyمعظم الإصلاحات تحديد أنواع للمعاملات. وفيstrictNullChecksأضف| undefinedحيث يمكن أن تغيب القيم، ثم تعامل معها بـ?.أو??أو فحصif. - حيث يجب أن ينتظر الإصلاح، ضع
// @ts-expect-errorمع سبب على السطر. بخلاف@ts-ignoreيبلّغ عن خطأ حالما تزول المشكلة، فتتقلص القائمة من تلقاء نفسها.
لا تلجأ إلى as any أو ! لإسكات الأخطاء بالجملة: كل واحد منها يخفي بالضبط الخطأ البرمجي الذي أُضيف الخيار لاكتشافه.
خيارات مفيدة لا يتضمنها Strict
هذه الخيارات منفصلة لأنها ترفض كودًا يكون صحيحًا في أحيان كثيرة. وكثير من المشاريع تفعّلها مع ذلك.
| الخيار | ما يفعله |
|---|---|
noUncheckedIndexedAccess | يتضمن نوع arr[i] وrecord[key] القيمة undefined |
exactOptionalPropertyTypes | يقبل debug?: boolean غياب المفتاح لكنه لا يقبل debug: undefined |
noImplicitReturns | يجب أن يعيد كل مسار في دالة لها قيمة إعادة قيمةً (TS7030) |
noImplicitOverride | يجب أن تحمل الدالة التي تعيد تعريف دالة الصنف الأساسي override (TS4114) |
noFallthroughCasesInSwitch | يجب أن ينتهي كل case غير فارغ بـ break أو return أو throw (TS7029) |
noUnusedLocals، noUnusedParameters | المتغيرات والمعاملات غير المستخدمة أخطاء |
noPropertyAccessFromIndexSignature | المفاتيح القادمة من index signature يجب أن تستخدم obj["key"]، لا obj.key |
الخيار noUncheckedIndexedAccess هو الذي يكتشف أكثر الأخطاء البرمجية الحقيقية. عند تفعيله:
const scores = [90, 85];
const d: Record<string, number> = {};
const third: number = scores[2]; // error TS2322: Type 'number | undefined' is not assignable to type 'number'.
const c: number = d["x"]; // same error
const safe = scores[2] ?? 0; // number
for (const s of scores) { // for...of is not affected: s is number
console.log(s);
}
يفعّل tsc --init في TypeScript 7 الخيارين noUncheckedIndexedAccess وexactOptionalPropertyTypes في الإعداد الذي يولّده، بجانب strict.
الأسئلة الشائعة
ماذا يفعل الوضع الصارم في TypeScript؟
يفعّل "strict": true مجموعة من الفحوص الأشد: noImplicitAny وstrictNullChecks وstrictFunctionTypes وstrictBindCallApply وstrictPropertyInitialization وnoImplicitThis وuseUnknownInCatchVariables وstrictBuiltinIteratorReturn. معًا تمنع ظهور any بصمت، وتجعل null وundefined جزءًا من نظام الأنواع.
هل الوضع الصارم مفعّل افتراضيًا في TypeScript؟
في TypeScript 7 نعم: القيمة الافتراضية لـ strict هي true، لذلك يحصل المشروع الذي لا يحدد strict على كل الفحوص الصارمة. ويكتب tsc --init أيضًا "strict": true صراحة. وللتخلي عنه عليك أن تكتب "strict": false.
هل يمكن إيقاف فحص صارم واحد مع إبقاء البقية؟
نعم. الخيارات الفردية تتقدم على strict: { "strict": true, "strictNullChecks": false } يُبقي كل الفحوص الصارمة عدا فحص null. وهذه هي الطريقة المعتادة لنقل قاعدة كود كبيرة خيارًا بعد خيار.
هل الوضع الصارم في TypeScript هو نفسه "use strict" في JavaScript؟
لا. "use strict" وضع وقت تشغيل في JavaScript يغيّر سلوك الكود. أما strict في TypeScript فيغيّر فقط ما يبلّغ عنه مدقق الأنواع. يُخرج TypeScript 7 دائمًا "use strict" للناتج الذي ليس وحدة، وalwaysStrict: false أصبح خيارًا مُزالًا.
هل يتضمن strict الخيار noUncheckedIndexedAccess؟
لا. noUncheckedIndexedAccess وexactOptionalPropertyTypes وnoImplicitReturns وnoImplicitOverride وnoFallthroughCasesInSwitch خيارات مستقلة تفعّلها بنفسك. ويفعّل tsc --init أول اثنين منها في الإعداد الذي يولّده.