דילוג לתוכן המרכזי
מודול 2 · שיעור 2 מתוך 24/14 בקורס~15 min
שיעורי מודול (2/2)

איגודים וצמצום

בעולם האמיתי, למשתנים ולתגובות API לא תמיד יש סוג קבוע אחד. TypeScript מציע Type Union לטיפול בשונות, ו-Type Narrowing כדי לפעול עליהם בבטחה בזמן ריצה.


סוגי איגוד

סוג איחוד מאפשר למשתנה לקבל ערכים מסוגים שונים. זה בא לידי ביטוי באמצעות סמל הפס האנכי (|):

TS
let result: number | string;
result = 42; // Valid
result = 'Error 404'; // Valid

עם זאת, כאשר עובדים עם סוג איגוד, לא נוכל לקרוא ישירות לשיטות ששייכות רק לאחד מהסוגים (לדוגמה, לא נוכל לקרוא ל-.toUpperCase() אם המשתנה יכול להיות גם number). ראשית עלינו "לצמצם" את הסוג.


סוג צמצום

Type Narrowing הוא התהליך שבו TypeScript מנתח מבני זרימת בקרה (כגון if או switch) כדי להסיק סוג ספציפי יותר עבור משתנה בזמן ריצה.

ישנן מספר דרכים לבצע צמצום:

1. המפעיל typeof

אידיאלי להבחין בין סוגים פרימיטיביים:

TS
function printLength(value: string | number) {
  if (typeof value === 'string') {
    // TypeScript knows 'value' is a string here
    console.log(value.length);
  } else {
    // TypeScript knows 'value' is a number here
    console.log(value.toFixed(2));
  }
}

2. המפעיל in

משמש כדי לבדוק אם קיים מאפיין ספציפי על אובייקט:

TS
interface Fish {
  swim: () => void;
}
interface Bird {
  fly: () => void;
}

function move(animal: Fish | Bird) {
  if ('swim' in animal) {
    animal.swim(); // Narrowing to Fish
  } else {
    animal.fly(); // Narrowing to Bird
  }
}

איגודים מופלים

דפוס איגודים מופלים מורכב מיצירת אובייקטים החולקים רכוש משותף עם ערך מילולי ייחודי (הנקרא מפלה). TypeScript מזהה את המאפיין הזה ומצמצמת אוטומטית את הסוג בתוך בלוקים מותנים.

TS
interface SuccessResponse {
  status: 'success'; // Literal discriminator
  data: string;
}

interface ErrorResponse {
  status: 'error'; // Literal discriminator
  errorMessage: string;
}

type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(response: ApiResponse) {
  if (response.status === 'success') {
    console.log('Data received:', response.data);
  } else {
    console.error('An error occurred:', response.errorMessage);
  }
}

נסה זאת בעצמך

תרגיל 1: סוגי איגוד

פעילות גופנית#ts.m2.l2.e1
ניסיונות: 0טוען...

הכריז על משתנה בשם id שיכול להיות מספר או מחרוזת. אתחול אותו תחילה עם המספר 101, ולאחר מכן הקצה את ערך המחרוזת 'USER-101'.

טוען עורך...
הצג רמז

השתמש ב- | אופרטור לחיבור מספר ומחרוזת בהצהרת משתנה let.

הפתרון זמין לאחר 3 ניסיונות

תרגיל 2: צמצום סוג בסיסי

פעילות גופנית#ts.m2.l2.e2
ניסיונות: 0טוען...

צור פונקציה בשם formatInput שמקבלת קלט פרמטר מסוג מחרוזת או מספר. אם הקלט הוא מחרוזת, החזר קלט שהומר לאותיות רישיות. אם זה מספר, החזר קלט כפול 2. ציין סוגים במפורש.

טוען עורך...
הצג רמז

השתמש בסוג קלט === 'מחרוזת' בתוך בלוק if כדי להסיע את ההתנהגות.

הפתרון זמין לאחר 3 ניסיונות

תרגיל 3: צמצום עם 'in'

פעילות גופנית#ts.m2.l2.e3
ניסיונות: 0טוען...

בהינתן שני הממשקים Car (עם שיטה הנעה) ו-Boat (עם מפרש שיטה), כתוב פונקציה בשם moveVehicle שמקבלת פרמטר רכב מסוג Car או Boat. אם לרכב יש את המאפיין drive, הפעל את שיטת drive() . אחרת, בצע את שיטת sail() .

טוען עורך...
הצג רמז

השתמש באופרטור in בצורה 'סע' ברכב כדי לצמצם את הממשק.

הפתרון זמין לאחר 3 ניסיונות

תרגיל 4: צורת איחוד מופלת

פעילות גופנית#ts.m2.l2.e4
ניסיונות: 0טוען...

הגדר סוג צורה שהיא איחוד של שני סוגים: עיגול וריבוע. למעגל יש מאפיין סוג שהוגדר ל'מעגל' (ערך מילולי) ורדיוס (מספר). לריבוע יש מאפיין סוג המוגדר ל'ריבוע' (ערך מילולי) וצד (מספר). לאחר מכן כתוב פונקציה getArea שמקבלת צורה מסוג Shape ומחזירה את השטח כמספר (עבור מעגל Math.PI * רדיוס * רדיוס, עבור צד מרובע * צד).

טוען עורך...
הצג רמז

השתמש ב-shape.kind === 'מעגל' בתוך getArea כדי להבחין בין הסוג ולחשב את השטח הנכון.

הפתרון זמין לאחר 3 ניסיונות