גם אני פעם אהבתי JavaScript, אבל מאז שגיליתי את TypeScript, צורת הפיתוח שלי השתנתה ואני לא מסתכל אחורה מאז.
במאמר זה אני מקווה לשכנע את מי שעדיין לא מכיר את השפה, לטעום, להנות ולהזניק את הקריירה.
מה הבעיה? קחו TypeScript
נתחיל בשאלה תמימה; כמה זה 2+2? אני מבקש ממי שכבר יודע את התשובה שלא ירים את ידו.
מכייוון שזאת שאלה שלא מכסים באינפי ובאלגברה ליניארית, אין לנו ברירה אלא לכתוב פונקציה שתחשב חיבור בין שני מספרים.
function sum(a, b) {
return a+b
}
באופן לא מפתיע אם תריצו את הקוד הבא תקבלו את התוצאה הנכונה.
sum(2, 2)
// 4
זאת גישה נאיבית לפונקציה. יש כאן הנחה סמויה שהערכים שנעביר לפרמטרים של הפונקציה יהיו תמיד מספריים. אבל רגע, מה יקרה אם אנחנו נעביר ערכים שמגיעים משדה טקסט, או API שמחזיר ערך מספרי בצורה של מחרוזת?
sum('2', 2)
// '22'
אבוי! עכשיו לכו תסבירו למורה שאתם מתכנתים מדופלמים וזה אשמת JavaScript והמרת הערכים העקומה שלה, ואין שום הצדקה לשלוח אתכם בחזרה לגן חובה!
אז מה קרה כאן? הרי הכל בעצם חוקי לגמרי. ב-JS יש רק סוג אחד משמעותי של משתנה – אובייקט. ולכן כל הקוד הבא עובר בשלום:
let a = 1
a = 2
a = '2'
a = {}
זה נובע מכך ש-JS היא שפה שהיא loosely typed. הכל הולך. כמו שראיתם למעלה זה מתכון לצרות. את זה תסביר לכם כל מתכנתת שהגיעה מ-Java לדוגמה. אלא אם היא הגיעה מ-Python ואז היא לא תבין מה הבעיה (אל תקשיבו לה!).
כאן TypeScript נכנסת לעזרה. בחברת מיקרוסופט הבינו את הבעיה ופיתחו שפה שרוכבת מעל JS.
כלומר, אם תבחרו לכתוב קוד JS סטנדרטי ב-TS אין שום בעיה להריץ אותו.
בסופו של דבר הקוד שלכם יתקמפל ל-JS הכי סטנדרטית שיש, רק עם הקוד הנדרש בשביל להגן על סוגי המשתנים שלכם. על הדרך תחטפו צעקות מימין ומשמאל, אם לא תקפידו על העקרונות.
אם ב-JS נכתוב משהו כמו:
let a = 1
את אותו הקוד נכתוב ב-TS באופן הבא:
let a: number = 1
TS מספיק חכמה בשביל להבין מה רציתם להגיד, ולכן האמת שאתם יכולים לכתוב גם שם את אותו הקוד שלמעלה, אבל יש דברים שיעבדו לכם מאותו הרגע ויש דברים שלא.
let a = 1
a = 2 // ok
a = '2' // not ok
בכל מקום שבו יש צורך, חשוב מאד לציין מה סוג הנתונים שנכנסים ויוצאים. הנה דוגמה שכזאת. הפונקציה מקבלת מספרים ומחזירה מספר. לכן זה לא יעבור בשלום אם ננסה לאחד בין תוצאת הפונקציה למספר וננסה לשים את התוצאה בתוך משתנה שהוגדר בתור מחרוזת:
בשנים האחרונות תפסה TS תאוצה גדולה. ריאקט ו- Vue תומכות בה באופן רשמי, אנגולר עובדת רק איתה ובאופן כללי הרבה ספריות NPM מכילות תמיכה מסודרת ב-TS.
מחלקה עם קלאסה
עד עכשיו רק גירדנו את פני השטח. להשתעשע עם משתנים ופונקציות זה מאד נחמד, אבל קוד מסודר אמור להכיל גם מחלקות.
JS תומכת במחלקות לכאורה מאז תקן ES6, אבל בפועל מדובר כאן על עטיפה דקה מאד מסביב לאובייקטים רגילים. TS לוקחת את זה הרבה מאד צעדים קדימה ומממשת עקרונות קלאסיים של OOP בצורה מוכרת ומסודרת.
class MyClass {
public static className = 'MyClass' // MyClass.className
private secret = 'secret' // Can’t access from the outside
public info = 'info' // Publicly available
constructor() {
console.log('hello world')
}
private secretFunc() {
// can't access from outside
}
publicFunc() {
// no need to specify the modifier - it's public by default
}
}
כמו שאתם רואים יש כאן שדות פרטיים וסטטיים המקובלים מאד בתכנות קלאסי.
אבל למה להיעצר כאן? יש גם אינטרפייסים ואוי לכם אם לא תממשו אותם! תחטפו נו נו נו מהקומפיילר.
נראה לכם שסיימנו? ממש לא. ניתן גם לייצר מחלקות ומתודות אבסטרקטיות:
abstract class MyClass {
foo(): void {}
}
class NewClass extends MyClass {
foo(): void {
console.log('foo')
}
}
const mc = new MyClass() // No go!
const nc = new NewClass()
nc.foo()
טיפוסים מתקדמים
גם בגזרת המשתנים הבודדים רק גירדנו את פני השטח. אנחנו רגילים לחשוב על כל דבר בתור אובייקט חסר אופי, אבל ב-TS ניתן להיות מאד ספציפיים לגבי האופי של האובייקט:
const coordinate: [number, number] = [1, 2]
ומה אם אתם לא זוכרים אם המשתנה הראשון הוא קו אורך או רוחב? אין שום בעיה. נשתמש באובייקט במקום במערך:
const coord: {lon: number, lat: number} = {lon: 1, lat: 2}
אתם אפילו יכולים להגדיר סוג ערך באופן רשמי לגמרי, כך שכל האפליקציה תוכל לחלוק בו:
type coordinate = {lon: number, lat: number}
const c: coordinate = {lon: 1, lat: 2}
בטח חשבתם שזה סוף המאמר. לא ולא! ניתן לייצר סוג משתנה שהוא איחוד של כמה אפשרויות.
תארו לעצמכם פונקציה שלוקחת שני ערכים ומדביקה אותם אחד לשני:
function concat(a, b) {
return a.toString() + b.toString()
}
concat(1,2) // '12'
concat('1', '2') // '12'
יופי. אבל מה מונע מאיתנו לנסות את זה?
concat({}, [])
ב-JS כלום! אבל ב-TS אפשר להגדיל את האפשרות ליותר מאחת, ובמקביל להגביל את המרחב ע"י שימוש ב-union types.
function concat(a: number | string, b: number | string) {
return a.toString() + b.toString()
}
גאוני, לא ככה?
פתרון גנרי
במשך השנים אימצה TS תכונות מקובלות משפות אחרות. אחת מאלה היא generics. ג'נריקס היא תכונה שקצת קשה להסביר על רגל אחת, אבל הרעיון שלה הוא שתהיה זיקה בין סוג המשתנה שפונקציה מקבלת לבין סוג הערך שהיא תחזיר, בלי לפרט יותר מידי מהו סוג הערך הזה.
בואו ניקח דוגמה של מערך שמכיל סוג אחד בלבד של משתנה. באופן עקרוני TS כבר מספקת לנו סוג משתנה כזה, אבל אנחנו עדיין יכולים לייצר מחלקה שמטפלת במערך ועושה דברים שמערך רגיל לא עושה.
class TypedArray<T> {
private arr: T[] = [];
addToMiddle(val: T) {
this.arr.splice(this.arr.length / 2, 0, val)
}
getValue(): T[] {
return this.arr
}
}
const a = new TypedArray<number>()
a.addToMiddle(1)
a.addToMiddle(2)
a.addToMiddle(3)
a.addToMiddle(4)
a.addToMiddle(5)
a.addToMiddle('6') // no go!
שימו לב שלא קבענו מה סוג המערך, אבל מה שהוא לא יהיה, הוא יישמור על אחידות סוג הנתונים.
לרוץ להשתמש ב-TypeScript עכשיו!
כאן המקום להגיד שניתן להתנסות ב-TS בקלי קלות ללא שום התקנה באתר הרשמי.
אם אתם חסידים של CodePen, כמובן שאתם מכוסים. צריך רק לבחור את ה-preprocessor המתאים תחת JS בהגדרות של ה-pen שלכם.
שתי האפשרויות ראויות מאד, אבל אם אתם מחפשים להתנסות בסביבה מאורגנת יותר, אפשרות אחת היא StackBlitz.
אם השתכנעתם ואתם רוצים להתחיל לפתח אצלכם על המחשב ב-TS מיד, הנה הצעדים הנדרשים עם עורך VSCode:
להתקין את VSCode אם לא עשיתם זאת עדיין.
להתקין תמיכה דרך NPM, או דרך ה-marketplace.
מה שמאד שימושי ונחמד זאת היכולת להגדיר שעל כל שינוי שתעשו בקבצים שלכם, העסק יתרענן מיד בכל שמירה.
אם אתם מפתחים ב-NodeJS, אנחנו מציעים לכם להתקין את ts-node-dev. בסיום ההתקנה הוסיפו את השורה הבאה ל-package.json בסעיף scripts:
"start": "ts-node-dev --respawn src/index.ts"
אם אתם מפתחים לפרונט, אני ממליץ לנסות את Parcel, שהיא מאד ידידותית למתחילים. לאחר ההתקנה פשוט יצרו לכם קובץ בסיס שנראה משהו כזה:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="index.ts"></script>
</body>
</html>
ויצרו קובץ index.ts עם הקוד הבא:
let a: number = 1
console.log(a)
הריצו את השורה הבאה:
parcel index.html
ומכאן לא רק שהפרוייקט יתחיל לרוץ בדפדפן, אלא גם הוא יתרענן במהירות בכל פעם שתעשו שינוי ותשמרו.
לסיכום
דיברנו על המגבלות של JS ואיך TS פותרת אותם ע"י הוספה של סוגי משתנים מעליה.
דיברנו גם על עקרונות בסיסיים של OOP ואיך הם מיושמים, כגון סוגי משתנים מתקדמים, איחודים וג'נריקס.
בסופו של דבר סקרנו גם את האפשרויות השונות לפתח ב-TS, בין אם זה באופן מקוון ובין אם מקומית.
וכעת זה תלוי רק בכם. קחו את יכולות התכנות שלכם לרמה אחרת לגמרי עם TypeScript.
בהצלחה!