לדלג לתוכן

5.1 הקדמה לטייפסקריפט פתרון

פתרון - הקדמה לטייפסקריפט

פתרון תרגיל 1

א. הקמת הפרויקט:

mkdir ts-intro
cd ts-intro
npm init -y
npm install -D typescript

ב. קובץ tsconfig.json:

{
    "compilerOptions": {
        "target": "ES2020",
        "module": "ESNext",
        "strict": true,
        "outDir": "dist",
        "rootDir": "src",
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
    },
    "include": ["src/**/*"]
}

ג. קובץ src/index.ts:

let message: string = "Hello from TypeScript!";
console.log(message);

ד. קומפילציה והרצה:

npx tsc
node dist/index.js

פתרון תרגיל 2

הוספת type annotations:

let firstName: string = "Alice";
let lastName: string = "Smith";
let age: number = 25;
let isLoggedIn: boolean = true;
let score: number = 98.5;
let greeting: string = `Hello, ${firstName}!`;

בדיקת שגיאות:

firstName = 42;       // ERROR: Type 'number' is not assignable to type 'string'
age = "twenty-five";  // ERROR: Type 'string' is not assignable to type 'number'
isLoggedIn = 1;       // ERROR: Type 'number' is not assignable to type 'boolean'

כל שלוש ההשמות נותנות שגיאה. שימו לב שגם isLoggedIn = 1 לא עובד - שלא כמו JS רגיל שמתייחס ל-1 כ-truthy, טייפסקריפט לא מאפשרת להכניס מספר למשתנה בוליאני.

פתרון תרגיל 3

let a = 42;          // number
let b = "hello";     // string
let c = true;        // boolean
let d = [1, 2, 3];   // number[]
let e = { name: "Alice", age: 30 }; // { name: string; age: number }
let f = null;        // null
let g = undefined;   // undefined
let h = Math.random() > 0.5 ? "yes" : "no";    // string
let i = Math.random() > 0.5 ? 42 : "hello";    // string | number

נקודות מעניינות:
- f מוסק כ-null (לא any) - מה שאומר שאפשר להכניס בו רק null
- g מוסק כ-undefined
- h מוסק כ-string (לא "yes" | "no") כי שני הענפים הם מחרוזות
- i מוסק כ-string | number - טיפוס איחוד, כי TS לא יודעת איזה ענף ירוץ

פתרון תרגיל 4

function calculateArea(width: number, height: number): number {
    return width * height;
}

function formatName(first: string, last: string): string {
    return `${first} ${last}`;
}

function isAdult(age: number): boolean {
    return age >= 18;
}

function describePerson(name: string, age: number, city: string = "Unknown"): string {
    return `${name} is ${age} years old and lives in ${city}`;
}

let area: number = calculateArea(5.0, 3.0);
let fullName: string = formatName("Alice", "Smith");
let adult: boolean = isAdult(20);
let description: string = describePerson("Bob", 25, "Tel Aviv");
let description2: string = describePerson("Charlie", 30);

console.log(area);        // 15
console.log(fullName);    // "Alice Smith"
console.log(adult);       // true
console.log(description); // "Bob is 25 years old and lives in Tel Aviv"
console.log(description2); // "Charlie is 30 years old and lives in Unknown"

שינויים מפייתון:
- float ו-int הפכו ל-number - בטייפסקריפט יש טיפוס מספרי אחד
- str הפך ל-string
- bool הפך ל-boolean
- def הפך ל-function
- f"..." הפך ל-`...`
- snake_case הפך ל-camelCase
- print() הפך ל-console.log()

הערה: ה-type annotations על המשתנים area, fullName וכו׳ לא הכרחיים - TS יכולה להסיק אותם מערך ההחזרה של הפונקציות. הוספנו אותם כאן לתרגול.

פתרון תרגיל 5

// ERROR 1: "25" is a string, not a number
let username: string = "Alice";
let userAge: number = 25;                  // fixed: removed quotes
let isActive: boolean = true;              // fixed: removed quotes

// ERROR 2: function returns string instead of number
function multiply(a: number, b: number): number {
    return a * b;                          // fixed: actual multiplication
}

// ERROR 3: function doesn't always return a string (missing return)
function getGreeting(name: string): string {
    if (name) {
        return "Hello, " + name;
    }
    return "Hello, stranger";              // fixed: added else return
}

// ERROR 4: "3" is a string in the array
let numbers: number[] = [1, 2, 3, 4, 5];  // fixed: 3 instead of "3"

// ERROR 5: multiply returns number, not string
let result: number = multiply(5, 3);      // fixed: type is number

פתרון תרגיל 6

א. בלי strict, הקוד מתקמפל בלי שגיאות. הפרמטר name מקבל טיפוס any בשקט, והגישה ל-value.toString() לא נבדקת.

ב. עם strict, יש שתי שגיאות:
1. Parameter 'name' implicitly has an 'any' type - noImplicitAny דורש טיפוס מפורש
2. 'value' is possibly 'null' - strictNullChecks מונע גישה ל-property של null

ג. התיקונים:

function greet(name: string): void {
    console.log("Hello, " + name);
}

let value: string | null = null;
if (value !== null) {
    console.log(value.toString());
} else {
    console.log("value is null");
}

פתרון תרגיל 7

א. התקנה:

npm install -D tsx

ב. קובץ playground.ts:

function square(n: number): number {
    return n * n;
}

function repeat(str: string, times: number): string {
    let result = "";
    for (let i = 0; i < times; i++) {
        result += str;
    }
    return result;
}

console.log(square(5));          // 25
console.log(repeat("ha", 3));    // "hahaha"

הרצה:

npx tsx playground.ts

ג. השוואה:
- עם tsc + node: שני צעדים - npx tsc ואז node dist/playground.js
- עם tsx: צעד אחד - npx tsx playground.ts

tsx נוח יותר לפיתוח מהיר כי חוסך את צעד הקומפילציה.

פתרון תרגיל 8

גרסת JS:

function createProfile(name, age, hobbies) {
    return {
        name,
        age,
        hobbies,
        summary: `${name} is ${age} years old and enjoys ${hobbies.join(", ")}`
    };
}

let profile = createProfile("Alice", 30, ["reading", "coding"]);
console.log(profile);

גרסת TS:

function createProfile(
    name: string,
    age: number,
    hobbies: string[]
): { name: string; age: number; hobbies: string[]; summary: string } {
    return {
        name,
        age,
        hobbies,
        summary: `${name} is ${age} years old and enjoys ${hobbies.join(", ")}`
    };
}

let profile: { name: string; age: number; hobbies: string[]; summary: string } =
    createProfile("Alice", 30, ["reading", "coding"]);

console.log(profile);

שימו לב שטיפוס ההחזרה ארוך ומסורבל. בשיעור הבא נלמד על interface ו-type שמאפשרים להגדיר טיפוסים בשם ולמנוע חזרות.

תשובות לשאלות

  1. טייפסקריפט היא ג׳אווהסקריפט עם טיפוסים סטטיים. היא מוסיפה בדיקת טיפוסים בזמן קומפילציה, שלא קיימת ב-JS. כל קוד JS הוא קוד TS תקין, אבל לא להפך.

  2. לא, טייפסקריפט לא רצה ישירות בדפדפן. הדפדפן מבין רק JavaScript. צריך לקמפל את הקוד מ-TS ל-JS לפני שהדפדפן יכול להריץ אותו. הטיפוסים מוסרים בתהליך הקומפילציה.

  3. הקומפיילר tsc (TypeScript Compiler) עושה שני דברים: בודק שגיאות טיפוסים, וממיר את הקוד ל-JavaScript על ידי הסרת כל ה-type annotations.

  4. strict mode מפעיל את כל הבדיקות המחמירות - strictNullChecks, noImplicitAny, ועוד. בלי strict mode, טייפסקריפט מתעלמת מהרבה שגיאות ומפספסת את רוב היתרונות שלה. זה כמו להרכיב חגורת בטיחות בלי לסגור אותה.

  5. בפייתון type hints הם רק רמזים - פייתון לא אוכפת אותם בזמן ריצה. אפשר להעביר int לפונקציה שמצפה ל-str ופייתון לא תתלונן. בטייפסקריפט הטיפוסים נאכפים על ידי הקומפיילר - קוד עם שגיאות טיפוסים לא יתקמפל.

  6. type inference (הסקת טיפוסים) היא היכולת של טייפסקריפט להבין את הטיפוס בלי שנכתוב אותו. למשל: let x = 5 - TS יודעת ש-x הוא number בלי שנכתוב let x: number = 5. TS מסתכלת על הערך ומסיקה את הטיפוס.

  7. חובה לכתוב type annotation בפרמטרים של פונקציות (TS לא מסיקה אותם), במשתנים שמוגדרים בלי ערך התחלתי, וכשרוצים טיפוס ספציפי יותר. אפשר לסמוך על הסקה כשמאתחלים משתנה עם ערך (כמו let x = 5), ב-return type של פונקציות פשוטות, ובכל מקום ש-TS מסיקה נכון.