Menu

TypeScript switch case: צמצום ובדיקות מיצוי

משפט switch ב-TypeScript: התחביר, איך כל case מצמצם טיפוס union, switch ממצה שלא מתקמפל כשחסר case, התבנית switch (true), נפילה ל-case הבא (fallthrough) ו-scope של בלוקים.

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

משפט switch ב-TypeScript הוא ה-switch של JavaScript עם בדיקת טיפוסים. הוא משווה ערך לכל case עם ===, מריץ את הענף שמתאים, ועוצר ב-break או ב-return. TypeScript מצמצם את הערך בתוך כל case ויכול לבדוק שכל ערך אפשרי מטופל.

תוויות מוערמות (case "sat": case "sun":) חולקות ענף אחד. return מסיים את הפונקציה, ולכן אין צורך ב-break אחריו.

תחביר

switch (expression) {
    case value1:
        // runs when expression === value1
        break;
    case value2:
    case value3:
        // runs for value2 or value3
        break;
    default:
        // runs when nothing else matched
}
  • ההתאמה משתמשת בשוויון מחמיר, ===: case 1 לא מתאים למחרוזת "1".
  • בלי break, return או throw, הביצוע ממשיך ל-case הבא (fallthrough).
  • default הוא אופציונלי ויכול לשבת בכל מקום, אם כי נהוג לשים אותו אחרון.
  • ערך case ש-TypeScript יכול להוכיח שאף פעם לא יתאים הוא השגיאה TS2678. לפרמטר מטיפוס "a" | "b", case "c": מדווח Type '"c"' is not comparable to type '"a" | "b"'., וזה תופס שגיאות הקלדה בתוויות.

צמצום בתוך כל case

בכל case, TypeScript יודע איזה ערך התאים ומצמצם את הטיפוס. זה הכי שימושי עם discriminated union: עשו switch על מאפיין התגית המשותף, וכל case רואה את הווריאנט המתאים עם המאפיינים שלו.

shape.radius מתקמפל רק ב-case של "circle". מחוץ לו, shape יכול להיות מלבן, שאין לו radius. אין default, והפונקציה עדיין עוברת בדיקת טיפוסים כמחזירה number, כי TypeScript רואה ששלושת ה-cases מכסים כל kind. תבניות נוספות שנבנות על זה נמצאות בעמוד discriminated unions.

switch ממצה עם never

הפונקציה למעלה מפסיקה להתקמפל אם מוסיפים צורה רביעית בלי case (TS2366, חסר return). זה עובד רק כשהפונקציה מחזירה ערך. לערובה שעובדת גם בקוד void ונותנת הודעה ברורה יותר, הוסיפו default שמשים את הערך ל-never:

index.ts(14,19): error TS2322: Type '{ kind: "triangle"; base: number; height: number; }' is not assignable to type 'never'.

אחרי ה-cases שטופלו, הטיפוס היחיד שנשאר ל-shape הוא הווריאנט של המשולש, ואי אפשר להשים אותו ל-never. השגיאה מציינת בדיוק מה חסר. הוסיפו case "triangle": return (shape.base * shape.height) / 2; וה-default רואה never, כך שהבלוק מתקמפל ומדפיס 9. ה-throw עדיין מגן מפני נתונים שגויים בזמן ריצה, כמו kind שהגיע מ-JSON והטיפוסים לא צפו אותו.

בסיסי קוד רבים עוטפים את הבדיקה בפונקציית עזר:

אותה טכניקה עובדת עם enums: עשו switch על ערך ה-enum והעבירו אותו ל-assertNever ב-default.

switch (true) לטווחים ולתנאים

switch משווה ערכים, ולכן טווחים דורשים טריק: עשו switch על true וכתבו תנאי בכל case. מאז TypeScript 5.3, התנאים האלה מצמצמים טיפוסים בדיוק כמו משפטי if.

ה-cases נבדקים לפי הסדר, אז שימו את הספציפי ביותר ראשון. אם זה קריא יותר מ-if / else if זה עניין של טעם; ההתנהגות זהה.

fallthrough ו-break

case שיש בו קוד אבל אין בו break, return או throw נופל ל-case הבא. זה כמעט תמיד באג. אפשרות הקומפיילר noFallthroughCasesInSwitch (לא חלק מ-strict) הופכת את זה לשגיאה TS7029, Fallthrough case in switch., ועדיין מתירה תוויות ריקות מוערמות.

fallthrough מכוון כזה עובד, אבל כש-noFallthroughCasesInSwitch מופעל צריך לכתוב אותו מחדש, למשל עם בדיקות if נפרדות. בדרך כלל זה גם ברור יותר.

משתנים בתוך cases

כל גוף ה-switch הוא בלוק אחד, ולכן const שהוצהר ב-case אחד נראה ב-cases האחרים (והצהרה חוזרת היא שגיאה). עטפו case בסוגריים מסולסלים כדי לתת לו scope משלו:

בלי הסוגריים, ה-const unit השני הוא שגיאת הקומפילציה TS2451, Cannot redeclare block-scoped variable 'unit'.

switch מול חיפוש באובייקט

כשכל case רק ממפה ערך לערך אחר, אובייקט עם טיפוס Record קצר יותר, ו-TypeScript בודק שכל מפתח קיים:

השמטה של מפתח היא שגיאת קומפילציה, וזה נותן את אותו מיצוי כמו בדיקת never. השאירו את switch למקרים שמריצים לוגיקה שונה, מצמצמים וריאנטים של union או חוזרים מוקדם.

שאלות נפוצות

איך כותבים משפט switch ב-TypeScript?

בדיוק כמו ב-JavaScript: switch (value) { case "a": ...; break; default: ... }. ה-cases מושווים עם ===. TypeScript מוסיף בדיקות: ערך case שאף פעם לא יכול להתאים לטיפוס שעליו עושים switch הוא שגיאה (TS2678), ובתוך כל case המשתנה מצומצם ל-case הזה.

איך הופכים switch לממצה ב-TypeScript?

הוסיפו default שמשים את הערך למשתנה מטיפוס never: default: { const unreachable: never = value; throw new Error(...) }. כשכל איברי ה-union מטופלים, הערך שם הוא never והקוד מתקמפל. כשאחד חסר, הקומפיילר מדווח על האיבר החסר (TS2322).

איך מטפלים בכמה cases עם אותו קוד ב-switch של TypeScript?

ערמו את התוויות בלי קוד ביניהן: case "sat": case "sun": return "weekend";. cases ריקים נופלים ל-case הבא. האפשרות noFallthroughCasesInSwitch מדווחת רק על cases שיש בהם קוד ואין בהם break או return, כך שתוויות מוערמות נשארות מותרות.

האם switch (true) מצמצם טיפוסים ב-TypeScript?

כן, מאז TypeScript 5.3. ב-switch (true) { case typeof x === "string": ... }, x מצומצם ל-string בתוך ה-case הזה, בדיוק כמו שהיה ב-if. זו חלופה קריאה לשרשרת של if/else if עם בדיקות של טווחים או טיפוסים.

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

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

להתחיל