שיעורי מודול (2/2)
איגודים וצמצום
בעולם האמיתי, למשתנים ולתגובות API לא תמיד יש סוג קבוע אחד. TypeScript מציע Type Union לטיפול בשונות, ו-Type Narrowing כדי לפעול עליהם בבטחה בזמן ריצה.
סוגי איגוד
סוג איחוד מאפשר למשתנה לקבל ערכים מסוגים שונים. זה בא לידי ביטוי באמצעות סמל הפס האנכי (|):
let result: number | string;
result = 42; // Valid
result = 'Error 404'; // Validעם זאת, כאשר עובדים עם סוג איגוד, לא נוכל לקרוא ישירות לשיטות ששייכות רק לאחד מהסוגים (לדוגמה, לא נוכל לקרוא ל-.toUpperCase() אם המשתנה יכול להיות גם number). ראשית עלינו "לצמצם" את הסוג.
סוג צמצום
Type Narrowing הוא התהליך שבו TypeScript מנתח מבני זרימת בקרה (כגון if או switch) כדי להסיק סוג ספציפי יותר עבור משתנה בזמן ריצה.
ישנן מספר דרכים לבצע צמצום:
1. המפעיל typeof
אידיאלי להבחין בין סוגים פרימיטיביים:
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
משמש כדי לבדוק אם קיים מאפיין ספציפי על אובייקט:
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 מזהה את המאפיין הזה ומצמצמת אוטומטית את הסוג בתוך בלוקים מותנים.
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: סוגי איגוד
הכריז על משתנה בשם id שיכול להיות מספר או מחרוזת. אתחול אותו תחילה עם המספר 101, ולאחר מכן הקצה את ערך המחרוזת 'USER-101'.
הצג רמז
השתמש ב- | אופרטור לחיבור מספר ומחרוזת בהצהרת משתנה let.
הפתרון זמין לאחר 3 ניסיונות
תרגיל 2: צמצום סוג בסיסי
צור פונקציה בשם formatInput שמקבלת קלט פרמטר מסוג מחרוזת או מספר. אם הקלט הוא מחרוזת, החזר קלט שהומר לאותיות רישיות. אם זה מספר, החזר קלט כפול 2. ציין סוגים במפורש.
הצג רמז
השתמש בסוג קלט === 'מחרוזת' בתוך בלוק if כדי להסיע את ההתנהגות.
הפתרון זמין לאחר 3 ניסיונות
תרגיל 3: צמצום עם 'in'
בהינתן שני הממשקים Car (עם שיטה הנעה) ו-Boat (עם מפרש שיטה), כתוב פונקציה בשם moveVehicle שמקבלת פרמטר רכב מסוג Car או Boat. אם לרכב יש את המאפיין drive, הפעל את שיטת drive() . אחרת, בצע את שיטת sail() .
הצג רמז
השתמש באופרטור in בצורה 'סע' ברכב כדי לצמצם את הממשק.
הפתרון זמין לאחר 3 ניסיונות
תרגיל 4: צורת איחוד מופלת
הגדר סוג צורה שהיא איחוד של שני סוגים: עיגול וריבוע. למעגל יש מאפיין סוג שהוגדר ל'מעגל' (ערך מילולי) ורדיוס (מספר). לריבוע יש מאפיין סוג המוגדר ל'ריבוע' (ערך מילולי) וצד (מספר). לאחר מכן כתוב פונקציה getArea שמקבלת צורה מסוג Shape ומחזירה את השטח כמספר (עבור מעגל Math.PI * רדיוס * רדיוס, עבור צד מרובע * צד).
הצג רמז
השתמש ב-shape.kind === 'מעגל' בתוך getArea כדי להבחין בין הסוג ולחשב את השטח הנכון.
הפתרון זמין לאחר 3 ניסיונות