strict mode הוא האפשרות "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. נשאר חריג אחד בכוונה: פרמטרים של מתודות שהוגדרו בתחביר מתודה (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 אם אתם צריכים את ההתנהגות הישנה בזמן המעבר. דרך שמשאירה את ה-build ירוק:
- הוסיפו
"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.
שאלות נפוצות
מה עושה strict mode ב-TypeScript?
"strict": true מפעיל קבוצה של בדיקות מחמירות יותר: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables ו-strictBuiltinIteratorReturn. יחד הן מונעות מ-any להופיע בשקט והופכות את null ו-undefined לחלק ממערכת הטיפוסים.
האם strict mode מופעל כברירת מחדל ב-TypeScript?
ב-TypeScript 7, כן: ברירת המחדל של strict היא true, כך שפרויקט בלי הגדרת strict מקבל את כל הבדיקות המחמירות. גם tsc --init כותב "strict": true במפורש. כדי לוותר על זה צריך לכתוב "strict": false.
אפשר לכבות בדיקה מחמירה אחת ולהשאיר את השאר?
כן. דגלים בודדים גוברים על strict: { "strict": true, "strictNullChecks": false } משאיר את כל הבדיקות המחמירות חוץ מבדיקת null. זו הדרך הרגילה להעביר בסיס קוד גדול דגל אחרי דגל.
האם strict mode של TypeScript זהה ל-"use strict" של JavaScript?
לא. "use strict" הוא מצב זמן ריצה של JavaScript שמשנה את התנהגות הקוד. strict של TypeScript משנה רק את מה שבודק הטיפוסים מדווח. TypeScript 7 תמיד פולט "use strict" לפלט שאינו מודול, ו-alwaysStrict: false היא עכשיו אפשרות שהוסרה.
האם strict כולל את noUncheckedIndexedAccess?
לא. noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitReturns, noImplicitOverride ו-noFallthroughCasesInSwitch הם דגלים נפרדים שמפעילים בעצמכם. tsc --init מפעיל את השניים הראשונים בקובץ ההגדרות שהוא יוצר.