אני מאמין שרוב הקוראים שמעו על טייפסקריפט, במאמר הזה ובמאמרים הבאים, שהקישורים אליהם יופיעו בתחתית המאמר הזה, אני אלמד טייפסקריפט מהבסיס, בעברית ובאופן פשוט. המטרה היא שסדרת המדריכים הזו תכנס, אחרי הפידבק שלכם ועיבוד נוסף, כנספח בספר שלי ללימוד ג'אווהסקריפט ואולי אחרי כן כפרק שלם. בסדרת המדריכים הזו התבססתי בעיקר על הדוקומנטציה של טייפסקריפט וה-Handbook המצוין שלהם באתר. בכל הנוגע לדוגמאות שימושיות ורעיון לסידור החומר נעזרתי גם באתר tutorialsTeacher.
למי שמעדיף לימוד עם סרטונים – החומר היחידי בעברית חוץ ממאמרים הוא סדרת הסרטונים של GoCode על טייפסקריפט (אני לא קשור ל-GoCode).
למי מיועד המדריך?
המדריך מיועד למתכנתים שמכירים ג'אווהסקריפט היטב. ברמה של עד תכנות אסינכרוני וכמובן ES6. בדיוק ברמה של הספר שלי "ללמוד ג'אווהסקריפט בעברית".
מה זה טייפסקריפט? למה צריך את זה?
טייפסקריפט (באנגלית Typescript) היא ג'אווהסקריפט עם סוגי מידע (באנגלית: Types). כלומר ג'אווהסקריפט שיש בה אכיפה של סוגי מידע. סוג מידע בג'אווהסקריפט בד"כ מקושר לסוג מידע פרימיטיבי. למשל בוליאני (True\False), מספר או מחרוזת טקסט. בג'אווהסקריפט אין אכיפה של סוגי מידע. מה זאת אומרת? אני אתן כדוגמה את הקוד הזה:
const weekDay = (val) => {
switch (val) {
case 1:
return 'Sunday';
break;
case 2:
return 'Monday';
break;
case 3:
return 'Tuesday';
break;
case 4:
return 'Wednesday';
break;
case 5:
return 'Thursday';
break;
case 6:
return 'Friday';
break;
default:
return 'Saturday';
}
}
console.log( weekDay(1) ); // "Sunday"
console.log( weekDay('1') ); // "Saturday"
כתבתי כאן פונקציה שממירה מספר ליום. אני מכניס מספר, למשל 1, ומקבל את השם. אבל אם אני מכניס את אותו המספר, אבל כמחרוזת טקסט, אני אקבל פלט שגוי. אם אני אכניס מספר לא נכון, כמו 8, אני אקבל פלט שגוי. אני יכול להכניס כל קלט שאני רוצה. התוצאה? תלויה במתכנת.
פתרון הגיוני לזה הוא לשים guards. כלומר משהו שבודק את הקלט כדי לוודא שזה באמת מה שאנו מצפים שיקרה. למשל:
if (isNaN(val) || val > 7 || val < 0) {
throw 'Invalid input';
}
val = parseInt(val);
וכמובן בדיקות יחידה שמנסות את הפונקציה בדרכים שונות, למשל זה:
describe('weekDay Function', function () {
it('should return the day of the week when value is between 1 to 6', () => {
const value = weekDay(1)
expect(value).toBe('Sunday');
});
it('should return the day of the week when value is string between 1 to 6', () => {
const value = weekDay('1')
expect(value).toBe('Sunday');
});
it('should return Saturday of the week when value is between 7', () => {
const value = weekDay(7)
expect(value).toBe('Saturday');
});
it('should throw error when input is less than 1', () => {
expect(() => {
weekDay(0);
}).toThrow();
});
it('should throw error when input is less more than 7', () => {
expect(() => {
weekDay(8);
}).toThrow();
});
it('should throw error when input is not a number', () => {
expect(() => {
weekDay('a');
}).toThrow();
});
});
See the Pen Jest Example by Ran Bar-Zik (@barzik-the-vuer) on CodePen.
זה מעולה, ומתכנתי ג'אווהסקריפט מנוסים יודעים שחלק מהבעיות שיש לנו הן בגלל בעיות של סוגי מידע. ג'אווהסקריפט היא שפה שאין לה, כברירת מחדל, בדיקה של סוגי מידע. אני יכול להעביר ולעשות מה שאני רוצה. החופשיות הזו גורמת לכתיבת הקוד להיות מאוד מהירה, אבל אם מדובר במתכנתים פחות מנוסים או במקומות שיש בהן פחות אכיפה של בדיקות, אז אנו בבעיה וזו בעייה קיימת.
דוגמה נוספת לבעיה כזו, ואפילו קלאסית, היא במידע בוליאני. למשל:
const someBoolFunc = (value) => {
if(value) {
console.log('value is true')
} else {
console.log('value is false')
}
}
someBoolFunc(true); // value is true
someBoolFunc(false); // value is false
someBoolFunc(); // value is false???
זה משהו קלאסי – אנו חושבים ומתכננים שכל ערך יהיה בוליאני. אבל אם ערך שהוא undefined מגיע, הוא false אוטומטית. אם הוא מגיע כ-0, כנ"ל. אבל 0 זה מספר! לא false! אז זהו. שג'אווהסקריפט מבצעת המרה אוטומטית של סוגי מידע פרימיטיביים. מספר לטקסט, טקסט לבוליאני, מספר לבוליאני וכך הלאה. בעוד שזו התנהגות שמתכנתי ג'אווהסקריפט מנוסים יודעים כבר לזכור, אלו שפחות נמצאים בבעיה.
אז הנה הבעיה, מה הפתרון?
בחברת מיקרוסופט היו לא מעט מהנדסים שנדרשו לתכנת בג'אווהסקריפט אחרי שהיו רגילים לשפות אחרות ומכך נוצר הצורך בטייפקסקריפט שמכניסה אכיפה של סוגים לתוך ג'אווהסקריפט. טייפסקריפט היא בקוד פתוח ומאוד פופולרית בגלל שלא מעט מתכנתים נתקלים בבעיה הזו של המרה. בעיה שטייפסקריפט מנסה לפתור. איך? אנו כותבים קוד ג'אווהסקריפט לכל דבר ועניין אבל בכל מקום שבו אנו צריכים אנו מגדירים את סוג המידע. בין אם מדובר בפונקציה או במקומות אחרים. אני רוצה בוליאני? אני אומר שאני רוצה בוליאני. רוצה מספר בין 1 ל-7? כנ"ל. תוכנת טייפסקריפט עוברת על הקוד שאנו כותבים, מוודאת שאין בו בעיות של מידע ואם הכל תקין היא ממירה אותו (תהליך ההמרה נקרא טרנספייל – מלשון Transpilation) לקוד ג'אווהסקריפט שהוא בעצמו רץ בסביבה של ג'אווהסקריפט, בין אם מדובר בדפדפן או בין אם מדובר בשרת.
איך זה עובד? בגדול אנו כותבים קוד טייפסקריפט ומציבים אותו בקובץ שהסיומת שלו היא ts, הטרנספיילר של טרנסקריפט רץ על הקבצים האלו וממיר אותם לג'אווהסקריפט כאשר אם יש שגיאות הוא מתריע. כאשר רוב הסביבות היום (למשל Next או create react app) באות אוטומטית עם טייפסקריפט כחלק מסביבת הפיתוח והבילד.
לשימוש מאוד ראשוני ולימודי, אנו נדגים עם Typescript playground של האתר הרשמי של טייפסקריפט. מדובר באתר שמבצע טרנספילציה לג'אווהסקריפט כמעט מייד. כשתכנסו לאתר תוכלו לראות מצד שמאל מקום שבו ניתן לכתוב בטייפסקריפט ומצד ימין את הפלט של ג'אווהסקריפט וכן את השגיאות שיש, אם יש.
ננסה להכניס את הקוד הבוליאני בדוגמה הקודמת, נראה שיש לנו שתי שגיאות:
Errors in code
Parameter 'value' implicitly has an 'any' type.
Expected 1 arguments, but got 0.
למה? כי ראשית לא הגדרנו בפונקציה את סוג המידע שהיא אמורה לקבל ושנית, באחת הקריאות לפונקציה (האחרונה), לא העברנו ארגומנט.
אפשר לראות שתהליך הטרינספול הצליח והקוד שלעיל הצליח להיות מתורגם לקוד ג'אווהסקריפט (הפתעה עצומה, זה קוד ג'אווהסקריפט נקי). אבל טייפסקריפט מתריעה על שתי בעיות.
הגדרה ראשונית של סוג מידע פרימיטיבי
בפונקציה ניתן להגדיר סוג מידע שאנו מצפים לו מארגומנט באמצעות נקודתיים אחרי הארגומנט וסוג המידע (אנו נרחיב על כך במאמר הבא, מבטיח). במקרה שלנו, Boolean. אם אנו אגדיר את סוג המידע בקוד הטייפסקריפט, אז הודעת השגיאה תעלם:
const someBoolFunc = (value: Boolean) => {
if(value) {
console.log('value is true')
} else {
console.log('value is false')
}
}
someBoolFunc(true); // value is true
someBoolFunc(false); // value is false
אפשר לראות שיש אגב בעורך הקוד שם השלמת טקסט מאוד חביבה שיכולה לעזור:
אם אני אקרא עם ערך לא בוליאני לפונקציה, כמו 0 למשל, אני אקבל שגיאה. אם אקרא לפונקציה ללא ארגומנט, גם אקבל שגיאה. השגיאות האלו נקראות שגיאת טרנסיפלציה והן אלו שמתריעות בפני שיש בעיה. נכון, אם יש Guards נכונים וגם בדיקות אני לא אצטרך את כל הטייפסקריפט הזה, אבל באמת יש בכל קוד שאתם כותבים בדיקות על הקלט וכן בדיקות יחידה ואינטגרציה? 🤔 לא? אז יש מצב שטייפסקריפט יכול לעזור לכם.
במאמר הזה למדנו על טייפסקריפט, הראנו את ה-sandbox ואפילו למדנו, מעט, על הגדרה של סוג בוליאני. במאמר הבא נדבר על סוגים נוספים שיש בטייפסקריפט, נשאר בתוך ה-TypeScript sandbox אבל לא לאורך זמן. בהמשך נלמד גם על סביבות יותר מתקדמות לכתיבה ופיתוח בטייפסקריפט.
10 תגובות
היי רן, כתבה מצוינת! אני ממש שמח שאנשים מתחילים להיכנס לעולם של טייפסקריפט. בתור אחד שהתחיל משפות כמו C#, טייפים זאת דרך חשובה ומצוינת לשמור עלינו מהאויב הכי גרוע שלנו – אנחנו עצמנו.
אני רוצה להתייחס לאחד העניינים בכתבה שלך שצריך להתייחס אליה – הגדרת את סוג המידע של הארגומנט הראשון בפונקציה someBoolFunc כBoolean ולא כboolean. אתה יכול לראות בצילומי המסך שלך שטייפסקריפט הציע לך את שניהם. אבל האמת הוא שיש ביניהם הבדל די חשוב.
boolean, כפי שהתיאור שלך הסביר, הוא אכן סוג מידע פרימיטיבי. עם זאת, Boolean הוא לא. מדובר באובייקט שכולל בתוכו מספר מאפיינים, כאשר הוא לרוב משמש כבילדר לסוג boolean. כשעובדים עם סוגי מידע, חשוב להשתמש בפרימיטיביים ולא באובייקטים שמייצרים אותם, כי הם יכולים לגרום לשגיאות לא צפויות.
הנה דוגמא בסטאקאוברפלוו שמסבירה את זה קלות:
https://stackoverflow.com/questions/64443288/what-is-the-difference-between-boolean-and-boolean-in-typescript
ישנן עוד שאלות כאלו, זאת אחת שמצאתי בזריזות כדי להביא את העניין לתשומת לבך.
תודה על ההשקעה בעבודתך המצוינת!
תודה על ההערה.
בעקבות ניסיתי בקונסול בדפדפן שתי אפשרויות:
typeof Boolean – החזיר לי function.
לעומת זאת, typeof boolean – החזיר לי undefined.
היי עודד,
אתה לא יכול לעשות typeof boolean.
כשאתה מריץ typeof X, התוצאה היא הסוג של X. הנה לדוגמא קוד פשוט שמדגים שימוש:
https://www.typescriptlang.org/play?#code/MYewdgzgLgBAtgTwGoEMBOMC8MpoK4CmA3AFCiQgA2BAdJSAOYAUUCADgSAGbzLoCURIA
אבל boolean הוא סוג בעצמו. אתה לא יכול לשאול סוג מה הסוג שלו – אין לזה משמעות.
לעומת זאת, Boolean, כפי שנאמר, הוא לא סוג – הוא אובייקט (וגם פונקציה) שעובד כconstructor של משתני boolean. לכן אתה יכול לשאול את Boolean מה הסוג שלו.
הנה ההגדרה הרשמית (ודוגמאות רלוונטיות) של typeof בג'אווהסקריפט:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
מקווה שזה ענה לך על השאלה.
היי אושר,
תודה על התגובה.
לא שאלתי שאלה אלא הגבתי על דבריך וחיזקתי אותם בעקבות כך שניסיתי לבדוק אותם בקונסול וזה יצא כמו שאתה אומר.
בכל מקרה, זה יצא לטובה כי הוספת והעמקת ולמדתי דברים חדשים גם מתגובתך.
אז תודה רבה על כך 🙂
ההסבר הכי טוב שקראתי!
תודה.
מעבר לתגובה של אושר, בלינק שאני מצרף פה למטה יש דוגמא יותר מורכבת, אבל גם יותר קרובה למה שקורה בפיתוח בחיים האמיתיים, לאיך הבטחון שאנחנו מרגישים מטייפסקריפט הוא בטחון מזוייף שכבר עדיף בלעדיו ולכתוב ישר ג'אווהסקריפט' היכן שאם, וזה אם גדול, אנחנו מודעים לכל הבעיות של השפה, אנחנו נכתוב מראש קוד הגנתי נגדן.
אגב, ריבוי הקוד ההגנתי הזה הוא אחת הסיבות הכי גדולות מדוע אני מתעב שפות עם שורשים ב-C, קרי: C, C++, C#, Java, JavaScript וכמובן איך אפשר לשכוח, Go (כן, כן, אני יודע שגו לא באמת יורשת מ-C, יש שם מספיק קווי דימיון כדי לשייך אותה למשפחה הזו כילדה מאומצת).
כמו שכתבתי בשרשור טוויטר, יש מספר שפות שמטרנספלות לג'אווהסקריפט ונותנות בטחון מוחלט בטייפים שלהם ובאופן משתמע מאפשרות לכתוב קוד שבו make illegal state unrepresentable.
טייפסקריפט היא לא אחת מהן. ממש לא!
הלינק למאמר: https://blog.mavnn.co.uk/2022/01/07/types-in-typescript.html
הי אוהד, אילו שפות אתה כן אוהב? ולמה
באופן אישי אני רואה את זה כחלק מהקלילות של JS
אם קיבלתי 0 זה אומר שלא צריך לבצע שום פעולות מכיון שאין איברים/פריטים ולכן אפשר לדלג על כל הלוגיקה ולסיים את הפונקציה
עכשיו לא צריך לבדוק האם קיבלתי FALSE או 0 ואז להמיר לFALSE . . .
שלום רן! אני קורא חדש באתר שנהנה מכל שורה… אולי אפילו קראתי קצת יותר מדי.
אני מבין שמאז שכתבת את ההערה הזו לגבי TS דעתך השתנתה?
https://internet-israel.com/%d7%9e%d7%93%d7%a8%d7%99%d7%9b%d7%99%d7%9d/babel/%d7%aa%d7%95%d7%a1%d7%a4%d7%99%d7%9d-%d7%91-babel/#comment-1007
לא. אני עדיין לא אוהב את טייפסקריפט אבל אני כבר מרים ידיים 🙂