tsconfig.json הוא קובץ ההגדרות של פרויקט TypeScript. כשמריצים tsc בלי ארגומנטים, הקומפיילר מחפש אותו בתיקייה הנוכחית (ואחר כך בתיקיות האב), קורא את האפשרויות שב-compilerOptions ובודק את הקבצים ש-include מפרט. דוגמה קטנה אבל שלמה:
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"strict": true,
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
ההגדרה הזו מקמפלת כל קובץ TypeScript שב-src ל-JavaScript בתוך dist, כקוד ES2022, לפי כללי המודולים של Node.js, עם כל הבדיקות הקפדניות מופעלות. npx tsc --init יוצר קובץ התחלתי ארוך יותר עם הערה על כל אפשרות.
הקובץ הוא JSON עם הערות: הערות //, הערות /* */ ופסיקים בסוף רשימה מתקבלים כולם.
הגדרה מומלצת להתחלה
לאפליקציה או לסקריפט של Node.js:
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"target": "es2024",
"lib": ["es2024"],
"module": "nodenext",
"types": ["node"],
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"sourceMap": true
},
"include": ["src"]
}
ההגדרה צריכה npm install --save-dev @types/node בשביל הטיפוסים של Node.js. עם module: "nodenext", השדה "type" ב-package.json קובע אם קובץ .ts הוא מודול ES ("type": "module") או CommonJS ("type": "commonjs", מה ש-npm init -y כותב). השתמשו ב-"type": "module" בפרויקטים חדשים שמשתמשים ב-import וב-export.
לקוד ש-bundler כמו Vite, esbuild או webpack בונה, ה-bundler כותב את ה-JavaScript ו-tsc רק בודק:
{
"compilerOptions": {
"target": "es2022",
"lib": ["es2022", "dom"],
"module": "preserve",
"noEmit": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"skipLibCheck": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
תבניות הפתיחה של frameworks (Vite, Next.js, Angular) יוצרות tsconfig.json משלהן. התחילו מהקובץ שלהן במקום להחליף אותו.
האפשרויות החשובות
| אפשרות | מה היא עושה | ברירת מחדל ב-TypeScript 7 |
|---|---|---|
target | גרסת ה-JavaScript של הפלט; תחביר חדש נכתב מחדש עבור targets ישנים | es2025 |
lib | טיפוסי ה-APIs המובנים שבודק הטיפוסים מכיר (Array.prototype.at, Map, document) | תואם ל-target, ובנוסף ה-DOM |
module | סוג קוד המודולים שנוצר וכללי המודולים שחלים | esnext |
moduleResolution | איך נתיבי import נמצאים בדיסק | nodenext או node16 עם ה-module המתאים, אחרת bundler |
strict | מפעיל את כל משפחת הבדיקות הקפדניות | true |
rootDir | התיקייה שהמבנה שלה משוכפל לתוך outDir | התיקייה שמכילה את tsconfig.json |
outDir | לאן הולכים קובצי ה-.js (וה-.d.ts) | ליד כל קובץ מקור |
include / exclude / files | אילו קבצים הם חלק מהפרויקט | כל קובץ .ts מתחת לתיקייה |
types | אילו חבילות @types נטענות בלי import | [], אף אחת |
noEmit | רק לבדוק, לא לכתוב כלום | false |
declaration | לכתוב גם קובצי הצהרת טיפוסים .d.ts | false |
sourceMap | לכתוב קובצי .js.map עבור דיבאגרים | false |
esModuleInterop | מאפשר ל-import x from "cjs-package" לעבוד עם חבילות CommonJS | true (אי אפשר לכבות) |
skipLibCheck | מדלג על בדיקת הטיפוסים של קובצי .d.ts, כולל אלה שב-node_modules | false |
target ו-lib
target קובע על איזו גרסת JavaScript הפלט צריך לרוץ. תחביר חדש יותר מה-target נכתב מחדש: עם "target": "es2017", שדה של מחלקה או ??= הופכים לקוד ישן יותר. ה-target הנמוך ביותר ש-TypeScript 7 מקבל הוא es2015 (es6); es5 הוסר.
target לא מוסיף APIs חסרים של זמן ריצה. לתאר אותם זה התפקיד של lib, ולספק אותם זה התפקיד של polyfill. lib אומר לבודק הטיפוסים אילו אובייקטים ומתודות מובנים קיימים. ברירת המחדל שלו נגזרת מ-target וכוללת גם את טיפוסי ה-DOM של הדפדפן, כך ש-document עובר את בדיקת הטיפוסים גם בפרויקט Node.js, אלא אם מגדירים את lib בעצמכם. שימוש במתודה מתקן חדש יותר מה-lib שלכם הוא שגיאת קומפילציה:
src/b.ts(1,24): error TS2550: Property 'toSorted' does not exist on type 'number[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2023' or later.
הדוגמאות להרצה בתיעוד הזה משתמשות ב-lib של es2022, ולכן toSorted, Object.groupBy והמתודות החדשות של Set לא זמינות בהן.
module ו-moduleResolution
ל-module יש שלושה ערכים הגיוניים לקוד חדש:
nodenext: לקוד ש-Node.js מריץ. כל קובץ הוא ESM או CommonJS לפי הסיומת שלו (.mts,.cts) או לפי"type"ב-package.jsonהקרוב ביותר, בדיוק כמו ש-Node מחליט. imports יחסיים במודולי ES צריכים סיומת קובץ, שנכתבת.jsלמרות שהמקור הוא.ts:import { add } from "./math.js".moduleResolutionמתאים את עצמו אוטומטית.preserve: לקוד ש-bundler מעבד. ה-imports נשארים כמו שנכתבו, והרזולוציה משתמשת בכלליbundler, שמאפשרים imports בלי סיומת.esnext: פלט מודולי ES פשוט, עם רזולוצייתbundler. זו ברירת המחדל כש-moduleלא מוגדר.
שגיאה ראשונה נפוצה עם ההגדרות של tsc --init נובעת מכך ש-npm init -y כותב "type": "commonjs":
src/main.ts(1,10): error TS1295: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'.
הקובץ משתמש ב-import, אבל package.json אומר שהפרויקט הוא CommonJS. שנו את "type" ל-"module". עמוד המודולים מסביר בפירוט imports ו-exports.
strict ואפשרויות הבדיקה
"strict": true מפעיל קבוצה של בדיקות בבת אחת: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, strictBuiltinIteratorReturn, noImplicitThis ו-useUnknownInCatchVariables. זו ברירת המחדל ב-TypeScript 7, והיא מופעלת בכל דוגמה להרצה כאן. קוד שנכתב למצב strict מצמצם את הטיפוס לפני שהוא משתמש בערך שעלול להיות חסר:
בלי הערת טיפוס, אי אפשר להסיק את הטיפוס של פרמטר, ו-noImplicitAny מדווח על כך:
index.ts(2,17): error TS7006: Parameter 'n' implicitly has an 'any' type.
strict לא כולל כל בדיקה שימושית. שתיים ששווה להוסיף הן noUncheckedIndexedAccess (לאיבר במערך או לחיפוש ב-index signature יש הטיפוס T | undefined) ו-exactOptionalPropertyTypes (אי אפשר להגדיר מאפיין אופציונלי במפורש ל-undefined); tsc --init מפעיל את שתיהן. בדיקות סגנון כמו noUnusedLocals, noImplicitReturns ו-noFallthroughCasesInSwitch כבויות כברירת מחדל.
אילו קבצים: include, exclude, rootDir, outDir
בלי include או files, הפרויקט מכיל כל קובץ .ts, .tsx ו-.d.ts בתיקייה ובתתי-התיקיות שלה. node_modules תמיד נשאר בחוץ. גם ה-outDir נשאר בחוץ, אבל רק כל עוד לא הגדרתם exclude: רשימת exclude משלכם מחליפה את ברירת המחדל הזו, אז הוסיפו אליה את תיקיית הפלט. include ו-exclude מקבלים תבניות glob:
{
"include": ["src", "scripts/**/*.ts"],
"exclude": ["src/**/*.test.ts"]
}
exclude רק מסנן את מה ש-include מצא. קובץ שקובץ כלול אחר מייבא עדיין מקומפל.
outDir הוא המקום שאליו הפלט הולך, ו-rootDir הוא החלק של עץ המקור שמשוכפל לתוכו: עם "rootDir": "./src", הקובץ src/api/users.ts הופך ל-dist/api/users.js. הגדירו את שניהם. ברירת המחדל של rootDir היא התיקייה שמכילה את tsconfig.json, ולכן אם מגדירים רק outDir בזמן שקובצי המקור נמצאים ב-src, TypeScript 7 עוצר עם:
error TS5011: The common source directory of 'tsconfig.json' is './src'. The 'rootDir' setting must be explicitly set to this or another path to adjust your output's file layout.
אפשרויות פלט: noEmit, declaration, sourceMap
"noEmit": trueהופך אתtscלבודק טיפוסים בלבד. השתמשו בזה כשכלי אחר (bundler,tsx, ה-type stripping של Node.js) מייצר את ה-JavaScript."declaration": trueכותב קובץ.d.tsלכל מודול, הטיפוסים בלי הקוד. ספריות צריכות את זה כדי שלמשתמשים שלהן יהיו טיפוסים.declarationMapמוסיף מפות כדי ש-"go to definition" יוביל לקוד ה-.ts."sourceMap": trueכותב קובצי.js.mapכדי שדיבאגרים ו-stack traces יצביעו על השורות ב-.ts."noEmitOnError": trueלא כותב כלום כל עוד יש שגיאות טיפוס. בלעדיו,tscמדווח על השגיאות ועדיין כותב את ה-JavaScript.
types, esModuleInterop ו-skipLibCheck
types מפרט את חבילות ה-@types שנטענות באופן גלובלי, בלי import. ברירת המחדל של TypeScript 7 היא רשימה ריקה, ולכן אחרי npm install --save-dev @types/node מוסיפים גם "types": ["node"]; אחרת process ו-require נשארים לא מוכרים (error TS2591: Cannot find name 'process'). כלי הרצת בדיקות עם פונקציות גלובליות, כמו describe של Jest, נכנסים לאותה רשימה.
esModuleInterop גורם ל-default imports של חבילות CommonJS לעבוד (import express from "express"). הוא תמיד מופעל ב-TypeScript 7, והגדרתו ל-false היא שגיאה.
skipLibCheck מדלג על בדיקת הטיפוסים של קובצי הצהרה. הוא מאיץ builds ומונע שגיאות בתוך node_modules שאין לכם דרך לתקן, במחיר של אי-זיהוי התנגשויות בין הטיפוסים של שתי ספריות. רוב הפרויקטים מפעילים אותו.
שיתוף הגדרות עם extends
extends טוען הגדרות אחרות ומאפשר לקובץ הזה לדרוס חלקים מהן:
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
compilerOptions מתמזגות אפשרות אחר אפשרות, ואילו include, exclude ו-files מהבסיס מוחלפים, ולא מתמזגים, אם הקובץ הזה מגדיר אותם. נתיבים בקובץ הבסיס מחושבים יחסית לקובץ הבסיס. extends מקבל גם חבילה: הפרויקט @tsconfig/bases מפרסם חבילה אחת לכל סביבה, למשל npm install --save-dev @tsconfig/node24 ואחר כך "extends": "@tsconfig/node24/tsconfig.json".
כדי לראות את ההגדרות הסופיות אחרי שכל ה-extends וברירות המחדל הוחלו, הריצו:
npx tsc --showConfig
אפשרויות שהוסרו ב-TypeScript 7
TypeScript 6 סימן את ההגדרות האלה כמיושנות, ו-TypeScript 7 הסיר אותן. הגדרות שעדיין משתמשות באחת מהן נכשלות עם error TS5108 או TS5102, למשל Option 'baseUrl' has been removed. Please remove it from your configuration.
| הגדרה שהוסרה | מה להשתמש במקומה |
|---|---|
"target": "es5" | es2015 ומעלה |
"moduleResolution": "node" (node10) או "classic" | nodenext או bundler |
"module": "amd", "umd", "system", "none" | nodenext, esnext או preserve, ו-bundler לפורמטים אחרים |
baseUrl | רשומות paths יחסיות לקובץ ה-tsconfig |
outFile | bundler |
downlevelIteration | כלום: targets מ-es2015 ומעלה תומכים באיטרציה באופן מובנה |
"esModuleInterop": false, "allowSyntheticDefaultImports": false, "alwaysStrict": false | מחקו את השורה; האפשרויות האלה תמיד מופעלות |
עמוד TypeScript 7 מפרט את שאר השינויים בגרסה הזו, כולל ברירות המחדל החדשות שהטבלה הזו לא מכסה.
שאלות נפוצות
מה זה tsconfig.json?
זה קובץ ההגדרות של פרויקט TypeScript. הנוכחות שלו מסמנת את התיקייה כשורש הפרויקט, compilerOptions קובע איך הקומפיילר בודק ומייצר קוד, ו-include, exclude או files קובעים אילו קבצים שייכים לפרויקט. הרצת tsc בלי ארגומנטים קוראת אותו.
איך יוצרים קובץ tsconfig.json?
הריצו npx tsc --init בתיקיית הפרויקט (כש-TypeScript מותקן). הפקודה כותבת tsconfig.json עם הגדרות מומלצות והערה על כל אפשרות. אפשר גם לכתוב את הקובץ ידנית; {} הוא tsconfig תקין שמשתמש בכל ברירות המחדל.
לאיזה ערך כדאי להגדיר את target ב-tsconfig?
לגרסת ה-JavaScript הישנה ביותר שהקוד צריך לרוץ עליה. עבור Node.js עדכני, es2022 ומעלה בטוח; ברירת המחדל של TypeScript 7 היא es2025. target קובע איזה תחביר חדש נכתב מחדש עבור מנועים ישנים, והוא גם בוחר את ה-lib שבברירת המחדל, אוסף ה-APIs המובנים שבודק הטיפוסים מכיר.
מה ההבדל בין module ל-moduleResolution?
module קובע איזה סוג קוד מודולים הקומפיילר כותב (import/export של ES או require של CommonJS) ואילו כללי מודולים חלים. moduleResolution קובע איך נתיב import כמו "./utils.js" או "lodash" נמצא בדיסק. השתמשו ב-nodenext לקוד ש-Node.js מריץ, וב-module: "preserve" (שמשמעותו רזולוציית bundler) לקוד ש-bundler מעבד.
אפשר לכתוב הערות ב-tsconfig.json?
כן. הקומפיילר קורא אותו כ-JSON עם הערות: הערות // ו-/* */ ופסיקים בסוף רשימה מותרים, ולכן tsc --init כותב קובץ מלא באפשרויות שהוכנסו להערה. כלים אחרים שקוראים אותו כ-JSON קפדני עלולים להיכשל עליהן.