הוסיפו ? אחרי שם הפרמטר כדי להפוך אותו לאופציונלי. מי שקורא לפונקציה יכול להשמיט אותו, ובתוך הפונקציה הטיפוס שלו כולל undefined.
TypeScript בודק את מספר הארגומנטים, ולכן בלי ה-? הקריאה הראשונה הייתה שגיאת קומפילציה: Expected 2 arguments, but got 1. (TS2554).
פרמטרים אופציונליים עלולים להיות undefined
מכיוון שמי שקורא לפונקציה יכול להשמיט אותו, הטיפוס של פרמטר אופציונלי בתוך הפונקציה הוא T | undefined. תחת strictNullChecks צריך לטפל במקרה של undefined לפני שמשתמשים בו כ-T.
Optional chaining (?.) ו-nullish coalescing (??) הם הכלים הרגילים כאן. כשערך הגיבוי קבוע, פרמטר עם ברירת מחדל קצר יותר.
ערכי ברירת מחדל לפרמטרים
ערך ברירת מחדל הופך את הפרמטר לאופציונלי עבור מי שקורא לפונקציה, ונותן לו בתוך הפונקציה טיפוס בלי undefined. הטיפוס מוסק מברירת המחדל, כך שהערת הטיפוס לרוב מיותרת.
מי שקורא לפונקציה רואה את החתימה repeat(text: string, times?: number, separator?: string). ברירות מחדל פועלות לפי הכלל של JavaScript: הן חלות כשהארגומנט הוא undefined, בין אם הושמט ובין אם הועבר במפורש, ולא כשהוא null. ביטוי ברירת מחדל יכול להשתמש בפרמטרים קודמים: function range(start: number, end = start + 10).
כללי סדר הפרמטרים
| הצהרה | עובר קומפילציה? | הערות |
|---|---|---|
(a: number, b?: number) | כן | פרמטרים אופציונליים באים בסוף |
(a?: number, b: number) | לא | TS1016: A required parameter cannot follow an optional parameter. |
(a = 0, b: number) | כן | אבל מי שקורא חייב לכתוב f(undefined, 5) כדי להשתמש בברירת המחדל |
(a: number, ...rest: number[]) | כן | פרמטר rest תמיד אחרון |
(a?: number, ...rest: number[]) | כן | אופציונלי לפני rest מותר |
פרמטר עם ברירת מחדל לפני פרמטר חובה הוא חוקי אבל מסורבל. הטיפוס שלו עבור מי שקורא הופך ל-number | undefined, ואף אחד לא נהנה לכתוב undefined כממלא מקום. אם צריך פרמטר ראשון גמיש, השתמשו במקום זאת באובייקט אפשרויות או ב-function overloading.
השמטה מול undefined
x?: number ו-x: number | undefined נראים דומים ויש להם אותו טיפוס בתוך הפונקציה. ההבדל הוא אצל מי שקורא: את הראשון אפשר להשמיט, את השני חובה להעביר.
השתמשו ב-| undefined לארגומנט חובה שמותר לו להיות בלי ערך, כך שכל מי שקורא לפונקציה ייאלץ לחשוב עליו. השתמשו ב-? כשהשמטה היא קריאה רגילה. (ההודעה באמת אומרת "1 arguments": זה הניסוח של TypeScript.)
פרמטרי rest
פרמטר rest, ...name: T[], אוסף כל מספר של ארגומנטים לתוך מערך. הוא חייב להיות הפרמטר האחרון.
פרישת מערך לתוך פרמטרים קבועים קפדנית יותר. פרמטר rest מקבל פרישה של כל number[], אבל פונקציה שהוצהרה כ-(a: number, b: number) מקבלת רק פרישה של tuple, כי TypeScript חייב לדעת את האורך:
function point(x: number, y: number) { return { x, y }; }
const list = [3, 4]; // number[]
point(...list);
// error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
const pair = [3, 4] as const; // readonly [3, 4]
point(...pair); // fine
גם לפרמטר rest יכול להיות טיפוס tuple, שנותן טיפוס לכל מיקום: ...args: [name: string, age?: number].
אובייקטי אפשרויות
ברגע שלפונקציה יש יותר משניים או שלושה פרמטרים אופציונליים, מי שקורא לה מאבד את המעקב אחרי המיקומים. אובייקט אפשרויות עם ברירות מחדל נותן ארגומנטים עם שמות, בלי חשיבות לסדר.
ה-= {} בסוף הופך את כל האובייקט לאופציונלי. בלעדיו, fetchData("/a") היא שגיאת קומפילציה (Expected 2 arguments, but got 1., TS2554), וב-JavaScript רגיל אותה קריאה הייתה זורקת TypeError בזמן ריצה, כי destructuring צריך אובייקט לקרוא ממנו.
פרמטרים אופציונליים בטיפוסי callback
בטיפוס פונקציה, ? פירושו "מי שקורא ל-callback הזה עשוי לא להעביר אותו". הוא לא אומר "ה-callback יכול לדלג עליו": callback תמיד יכול להתעלם מפרמטרים בסוף. לכן אל תסמנו פרמטרים של callback כאופציונליים רק כדי לאפשר ל-handlers לקבל פחות ארגומנטים.
// Too loose: every handler must now cope with index being undefined
type Visit = (item: string, index?: number) => void;
// Right: the caller always passes both; handlers may use only item
type VisitStrict = (item: string, index: number) => void;
const log: VisitStrict = (item) => console.log(item);
שאלות נפוצות
איך הופכים פרמטר לאופציונלי ב-TypeScript?
שמים ? אחרי השם שלו: function greet(name?: string). מי שקורא לפונקציה יכול להשמיט אותו, ובתוך הפונקציה הטיפוס שלו הוא string | undefined, ולכן בודקים אותו לפני השימוש. גם מתן ערך ברירת מחדל לפרמטר, name = "there", הופך אותו לאופציונלי ומסיר את ה-undefined בתוך הפונקציה.
האם פרמטר אופציונלי יכול לבוא לפני פרמטר חובה ב-TypeScript?
לא עם ?: (a?: number, b: number) היא שגיאה TS1016, "A required parameter cannot follow an optional parameter." פרמטר עם ערך ברירת מחדל יכול לבוא ראשון, אבל אז מי שקורא לפונקציה חייב להעביר undefined במפורש כדי להשתמש בברירת המחדל, ולכן בפועל פרמטרים אופציונליים ופרמטרים עם ברירת מחדל באים בסוף.
מה ההבדל בין x?: number לבין x: number | undefined?
בתוך הפונקציה שניהם number | undefined. ההבדל הוא במקום הקריאה: עם x?: number אפשר להשמיט את הארגומנט, ועם x: number | undefined חובה להעביר אותו, גם אם הערך הוא undefined. השמטה שלו נותנת שגיאה TS2554.
האם העברת null משתמשת בערך ברירת המחדל של הפרמטר?
לא. JavaScript מפעילה ברירת מחדל רק כשהארגומנט הוא undefined (מושמט או מועבר במפורש). null הוא ערך, ולכן הוא נשמר. בכל מקרה, תחת strictNullChecks TypeScript דוחה null לפרמטר מסוג number.
איך מעבירים מערך כארגומנטים נפרדים ב-TypeScript?
פורשים אותו: fn(...args). לפונקציה עם פרמטרים קבועים, המערך חייב להיות מטיפוס tuple כמו [number, number] או להגיע מ-as const; פרישה של number[] נותנת שגיאה TS2556 כי האורך שלו לא ידוע. פרישה לתוך פרמטר rest (...values: number[]) תמיד עובדת.