פונקציות

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

פרמטרים וערך מוחזר

function add(a: number, b: number): number {
    return a + b;
}

const multiply = (a: number, b: number): number => a * b;

add(2, '3');
// Argument of type 'string' is not assignable to parameter of type 'number'.

add(2);
// Expected 2 arguments, but got 1.

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

פרמטרים אופציונליים וברירות מחדל

function greet(name: string, greeting?: string): string {
    // greeting הוא string | undefined
    return `${greeting ?? 'שלום'} ${name}`;
}

function formatPrice(amount: number, currency = '₪'): string {
    // currency מוסק כ-string מברירת המחדל
    return `${currency}${amount.toFixed(2)}`;
}

greet('דנה');
formatPrice(19.9);

אובייקט כפרמטר

פונקציה עם יותר משניים-שלושה פרמטרים קריאה יותר כשהיא מקבלת אובייקט:

type SendEmailOptions = {
    to: string;
    subject: string;
    body: string;
    urgent?: boolean;
};

function sendEmail({ to, subject, body, urgent = false }: SendEmailOptions): void {
    console.log(`שולח ל-${to}${urgent ? ' (דחוף)' : ''}: ${subject}`);
}

sendEmail({ to: '[email protected]', subject: 'שלום', body: '...' });

Rest Parameters

function sum(...values: number[]): number {
    return values.reduce((total, value) => total + value, 0);
}

sum(1, 2, 3, 4);

טיפוס של פונקציה

כשפונקציה מקבלת פונקציה אחרת (callback), מתארים את החתימה שלה:

type Validator = (value: string) => boolean;

const isEmail: Validator = (value) => value.includes('@');   // value מוסק כ-string

function validateAll(values: string[], check: Validator): boolean {
    return values.every(check);
}

פונקציות אסינכרוניות

type User = { id: number; name: string };

async function fetchUser(id: number): Promise<User> {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
        throw new Error(`המשתמש לא נמצא (${response.status})`);
    }
    return response.json() as Promise<User>;
}

const user = await fetchUser(1);   // User
console.log(user.name);

פונקציה async תמיד מחזירה Promise<...>. שימו לב ל-as: TypeScript לא יכולה לדעת מה השרת החזיר, ואנחנו רק מבטיחים לה. בשיעור האחרון נראה איך לבדוק את זה באמת.

עומס (Overloads) - בקצרה

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

function parse(value: string): number;
function parse(value: string[]): number[];
function parse(value: string | string[]): number | number[] {
    return Array.isArray(value) ? value.map(Number) : Number(value);
}

const one = parse('5');           // number
const many = parse(['1', '2']);   // number[]

ברוב המקרים Union או Generics (שני השיעורים הבאים) פשוטים יותר.

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה הטיפוס של פרמטר אופציונלי greeting?: string בתוך הפונקציה?

    1. string | undefined
    2. null
    3. any
    4. string
    הצגת התשובה

    תשובה א. פרמטר אופציונלי יכול להיות חסר, ולכן צריך ברירת מחדל או בדיקה.

  2. מה מחזירה פונקציה async שמחזירה User?

    1. any
    2. void
    3. User
    4. Promise<User>
    הצגת התשובה

    תשובה ד. פונקציה async תמיד מחזירה Promise.