מודולים ו-tsconfig

פרויקט אמיתי מפוצל להרבה קבצים. השיעור הזה מסביר איך מייבאים ומייצאים טיפוסים, ואיך מגדירים את tsconfig.json כדי שהמהדר יעבוד בשבילכם ולא נגדכם.

ייצוא וייבוא של טיפוסים

// types.ts
export type Product = { id: number; name: string; price: number };
export type CartItem = { product: Product; quantity: number };
// cart.ts
import type { CartItem } from './types.ts';

export function cartTotal(items: CartItem[]): number {
    return items.reduce((sum, item) => sum + item.product.price * item.quantity, 0);
}

import type מסמן שמייבאים רק טיפוס, שנמחק לגמרי מה-JavaScript. זה עוזר לכלי build, וחובה כשמריצים ישירות ב-Node.js עם verbatimModuleSyntax.

סיומת בייבוא

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

  • Node.js מריץ .ts ישירות - מייבאים עם הסיומת האמיתית: './types.ts' (עם allowImportingTsExtensions).
  • Vite, Next.js - בלי סיומת בכלל: './types'. הכלי מוצא את הקובץ.

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

tsconfig.json מומלץ לפרויקט Node.js

{
  "compilerOptions": {
    "target": "ES2023",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",

    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,

    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true,
    "erasableSyntaxOnly": true,
    "noEmit": true,

    "skipLibCheck": true
  },
  "include": ["src"]
}

מה כל הגדרה עושה

הגדרהלמה
strictמפעיל את כל הבדיקות החשובות, כולל null. חובה.
noUncheckedIndexedAccessarray[i] ו-obj[key] יכולים להיות undefined, כמו במציאות
module: NodeNextייבוא וייצוא בדיוק כמו ש-Node.js מבין אותם
verbatimModuleSyntaxמחייב import type לטיפוסים, כדי שהסרה פשוטה תעבוד
erasableSyntaxOnlyשגיאה על תחביר שאי אפשר פשוט למחוק (enum, פרמטרים עם private בבנאי), כלומר מה ש-Node.js לא יריץ
noEmittsc רק בודק. Node.js או כלי ה-build מריצים
skipLibCheckלא בודק את קובצי הטיפוסים של ספריות: מהיר יותר, ובטוח

בפרויקט Vite או Next.js לא צריך לכתוב את זה לבד: ה-template מגיע עם tsconfig מוכן. כדאי רק לוודא ש-strict דלוק.

קובצי d.ts וטיפוסים של ספריות

רוב הספריות מגיעות עם טיפוסים. לחלק הישנות יש חבילה נפרדת מ-DefinitelyTyped:

npm install express
npm install --save-dev @types/express @types/node

קובץ .d.ts מכיל רק טיפוסים, בלי קוד. כך TypeScript יודעת מה יש בספרייה שנכתבה ב-JavaScript.

קיצורי נתיב

{
  "compilerOptions": {
    "paths": { "@/*": ["./src/*"] }
  }
}
import { Button } from '@/components/Button';   // במקום '../../../components/Button'

שימו לב: paths משפיע רק על בדיקת הטיפוסים. הכלי שמריץ את הקוד (Vite, bundler) צריך הגדרה תואמת משלו.

בדקו את עצמכם

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

  1. למה כותבים import type?

    1. זה חובה לכל import
    2. כדי לסמן שמייבאים רק טיפוס, שנמחק לגמרי
    3. זה מהיר יותר בזמן ריצה
    4. כדי לייבא JSON
    הצגת התשובה

    תשובה ב. זה חשוב לכלים שרק מסירים טיפוסים, כמו Node.js.

  2. מה עושה noUncheckedIndexedAccess?

    1. אוסר מערכים
    2. מאיץ קומפילציה
    3. מכבה בדיקות
    4. arr[i] מקבל טיפוס שכולל undefined, כמו במציאות
    הצגת התשובה

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