Menu

TypeScript strict mode: מה strict: true מפעיל

strict: true ב-tsconfig.json מפעיל משפחה של בדיקות טיפוסים: noImplicitAny, strictNullChecks, strictPropertyInitialization ועוד חמש. ראו מה כל אחת תופסת, איך מפעילים strict mode בפרויקט קיים, ואילו דגלים שימושיים לא כלולים ב-strict.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

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פרמטר או משתנה שהטיפוס שלו היה הופך בשקט ל-anyTS7006 Parameter 'x' implicitly has an 'any' type.
strictNullChecksשימוש בערך שעשוי להיות null או undefinedTS18048 'u' is possibly 'undefined'.
strictFunctionTypesהשמה של פונקציה שטיפוס הפרמטר שלה צר מהנדרשTS2322
strictBindCallApplyארגומנטים שגויים ל-.call, .bind ו-.applyTS2345
strictPropertyInitializationשדה מחלקה שאף פעם לא מקבל ערךTS2564 Property 'name' has no initializer and is not definitely assigned in the constructor.
noImplicitThisthis עם טיפוס 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 ירוק:

  1. הוסיפו "strict": true וכבו את הדגלים עם הכי הרבה שגיאות, בדרך כלל "strictNullChecks": false ו-"noImplicitAny": false.
  2. תקנו את השגיאות שנשארו, ואז הפעילו עוד דגל אחד וחזרו על התהליך.
  3. ב-noImplicitAny, רוב התיקונים הם הערות טיפוס לפרמטרים. ב-strictNullChecks, הוסיפו | undefined איפה שערכים יכולים להיות חסרים, ואז טפלו בזה עם ?., ?? או בדיקת if.
  4. איפה שתיקון צריך לחכות, שימו בשורה // @ts-expect-error עם סיבה. בניגוד ל-@ts-ignore, הוא מדווח שגיאה ברגע שהבעיה נעלמת, כך שהרשימה מתקצרת מעצמה.

אל תשתמשו ב-as any או ב-! כדי להשתיק שגיאות בכמויות: כל אחד מהם מסתיר בדיוק את הבאג שהדגל נוסף כדי למצוא.

דגלים שימושיים ש-strict לא כולל

הם נפרדים כי הם דוחים קוד שלעיתים קרובות הוא נכון. פרויקטים רבים מפעילים אותם בכל זאת.

דגלמה הוא עושה
noUncheckedIndexedAccessarr[i] ו-record[key] כוללים undefined בטיפוס שלהם
exactOptionalPropertyTypesdebug?: boolean מקבל מפתח חסר אבל לא debug: undefined
noImplicitReturnsכל מסלול קוד בפונקציה שמחזירה ערך חייב להחזיר (TS7030)
noImplicitOverrideמתודה שדורסת מתודה של מחלקת הבסיס חייבת לציין override (TS4114)
noFallthroughCasesInSwitchcase לא ריק חייב להסתיים ב-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 מפעיל את השניים הראשונים בקובץ ההגדרות שהוא יוצר.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל