Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Konfiguracja środowiska (tsconfig.json)

Wprowadzenie: Mapa Parku Jurajskiego

W poprzedniej lekcji poznaliśmy TypeScript jako zaawansowany system bezpieczeństwa dla naszego Parku Jurajskiego. Teraz nadszedł czas, aby zrozumieć, jak skonfigurować ten system - to tak, jakbyśmy projektowali mapę parku, określali strefy bezpieczeństwa i ustawiali poziomy dostępu.

W świecie TypeScript, tę konfigurację zapewnia plik tsconfig.json. To właśnie on określa, jak działa kompilator TypeScript, jakie opcje są włączone, jak rygorystyczne są reguły typowania i wiele innych aspektów.

Dr. Henry Wu, główny genetyk parku, lubi mówić: "Kontrola to iluzja". Ale w przypadku TypeScript, odpowiednia konfiguracja daje nam rzeczywistą kontrolę nad naszym kodem.

Tworzenie pliku tsconfig.json

Zacznijmy od utworzenia podstawowego pliku konfiguracyjnego dla naszego systemu zarządzania Parkiem Jurajskim:

1# Jeśli masz zainstalowany TypeScript globalnie, możesz użyć:
2tsc --init
3
4# Lub za pomocą npx:
5npx tsc --init

Ta komenda wygeneruje podstawowy plik tsconfig.json z najważniejszymi opcjami (większość z nich będzie zakomentowana). Dla naszego parku dinozaurów, możemy utworzyć niestandardową konfigurację:

1{
2  "compilerOptions": {
3    "target": "es2016",
4    "module": "commonjs",
5    "outDir": "./dist",
6    "rootDir": "./src",
7    "strict": true,
8    "esModuleInterop": true,
9    "skipLibCheck": true,
10    "forceConsistentCasingInFileNames": true
11  },
12  "include": ["src/**/*"],
13  "exclude": ["node_modules", "**/*.spec.ts"]
14}

To tak, jakby Dr. Hammond przygotował wytyczne dotyczące funkcjonowania poszczególnych stref w parku.

Najważniejsze opcje konfiguracyjne

Podstawowa struktura projektu

Podobnie jak w parku potrzebujemy określić strefy dla różnych gatunków dinozaurów, w projekcie TypeScript musimy zdefiniować, gdzie znajdują się pliki źródłowe i gdzie będą generowane pliki wynikowe:

1{
2  "compilerOptions": {
3    "outDir": "./dist",    // Katalog wynikowy, gdzie będą generowane pliki .js
4    "rootDir": "./src",    // Katalog źródłowy, gdzie znajdują się pliki .ts
5    "baseUrl": ".",        // Bazowy URL dla ścieżek względnych
6    "paths": {             // Aliasy dla ścieżek importów
7      "@models/*": ["src/models/*"],
8      "@utils/*": ["src/utils/*"],
9      "@config/*": ["src/config/*"]
10    }
11  }
12}

To tak, jakbyśmy mieli mapę parku z oznaczeniami:

  • "src" to nasza główna baza operacyjna
  • "dist" to obszar dostępny dla zwiedzających
  • Mamy też skróty do ważnych miejsc w parku (laboratorium, centrum kontroli itp.)

Wersja ECMAScript

Podobnie jak park musi być kompatybilny z różnymi gatunkami dinozaurów, nasz kod TypeScript musi być kompatybilny z różnymi środowiskami JavaScript:

1{
2  "compilerOptions": {
3    "target": "es2016",     // Do jakiej wersji JS kompilować
4    "module": "commonjs",   // System modułów (commonjs, ES modules, etc.)
5    "lib": ["dom", "es2016", "dom.iterable", "scripthost"] // Biblioteki definicji
6  }
7}

W naszym parku:

  • "target" to jak określenie, z którymi gatunkami dinosaurów jesteśmy w stanie pracować
  • "module" to jak system transportu w parku (jeepy, monorail itp.)
  • "lib" to jak określenie, jakie narzędzia i sprzęt mamy do dyspozycji

Poziom restrykcyjności

W zależności od gatunków dinozaurów w parku, potrzebujemy różnych poziomów zabezpieczeń. Podobnie w TypeScript, możemy regulować poziom rygorystyczności sprawdzania typów:

1{
2  "compilerOptions": {
3    "strict": true,                // Włącza wszystkie poniższe opcje rygorystyczne
4    "noImplicitAny": true,         // Wymusza jawne deklarowanie typu "any"
5    "strictNullChecks": true,      // Wymusza sprawdzanie wartości null i undefined
6    "strictFunctionTypes": true,   // Bardziej rygorystyczne sprawdzanie typów funkcji
7    "strictBindCallApply": true,   // Sprawdzanie typów dla metod bind, call i apply
8    "strictPropertyInitialization": true, // Sprawdza, czy właściwości klas są inicjalizowane
9    "noImplicitThis": true,        // Wymusza jawne określanie typu "this"
10    "alwaysStrict": true           // Parsuje kod w trybie strict mode
11  }
12}

W kontekście Parku Jurajskiego:

  • strict: true
    to jak wprowadzenie najwyższego poziomu bezpieczeństwa we wszystkich sektorach parku
  • noImplicitAny
    to jak zasada "zawsze identyfikuj gatunek dinozaura przed umieszczeniem go w zagrodzie"
  • strictNullChecks
    to jak sprawdzanie, czy ogrodzenia są faktycznie podłączone do prądu, zamiast zakładania, że wszystko działa

Konfiguracja modułów i importów

Zarządzając parkiem, musimy mieć jasny system komunikacji między różnymi działami. W TypeScript konfigurujemy, jak moduły komunikują się ze sobą:

1{
2  "compilerOptions": {
3    "module": "esnext",            // System modułów
4    "moduleResolution": "node",    // Strategia rozwiązywania modułów
5    "esModuleInterop": true,       // Lepsza interoperacyjność z modułami CommonJS
6    "allowSyntheticDefaultImports": true, // Pozwala na import defaultowy z modułów bez eksportu domyślnego
7    "resolveJsonModule": true      // Pozwala na import plików JSON
8  }
9}

W parku:

  • moduleResolution
    to jak system komunikacji radiowej - określa, jak znajdujemy i kontaktujemy się z różnymi zespołami
  • esModuleInterop
    to jak zapewnienie, że starsze i nowsze systemy komunikacji działają razem
  • resolveJsonModule
    to jak możliwość odczytywania standardowych formularzy raportów

Opcje developerskie

Dr. Wu potrzebuje narzędzi do tworzenia nowych gatunków dinozaurów. My również potrzebujemy narzędzi developerskich:

1{
2  "compilerOptions": {
3    "sourceMap": true,            // Generuje pliki .map dla łatwiejszego debugowania
4    "declaration": true,          // Generuje pliki .d.ts z deklaracjami typów
5    "declarationMap": true,       // Generuje pliki .map dla plików .d.ts
6    "incremental": true,          // Przyspiesza kompilację przez cache poprzednich kompilacji
7    "tsBuildInfoFile": "./dist/.tsbuildinfo" // Plik z informacją o kompilacji
8  }
9}

W parku:

  • sourceMap
    to jak szczegółowa dokumentacja DNA każdego dinozaura - pomaga zrozumieć, co poszło nie tak
  • declaration
    to jak rejestr wszystkich gatunków dinozaurów
  • incremental
    to jak optymalizacja procesu klonowania, aby nie powtarzać tych samych procedur

Opcje dla projektów React

Jeśli używasz React (hipotetycznie, interaktywne atrakcje w Parku Jurajskim), przydadzą się dodatkowe opcje:

1{
2  "compilerOptions": {
3    "jsx": "react",               // Obsługa składni JSX
4    "jsxFactory": "React.createElement", // Funkcja używana do kompilacji JSX
5    "jsxFragmentFactory": "React.Fragment" // Komponent fragmentu
6  }
7}

To jak konfiguracja interaktywnych wyświetlaczy w centrum dla zwiedzających, które pokazują animacje i informacje o dinozaurach.

Konfiguracja dla specyficznych przypadków

Projekt Node.js dla systemu bezpieczeństwa parku

1{
2  "compilerOptions": {
3    "target": "es2018",
4    "module": "commonjs",
5    "outDir": "./dist",
6    "rootDir": "./src",
7    "strict": true,
8    "esModuleInterop": true,
9    "skipLibCheck": true,
10    "forceConsistentCasingInFileNames": true,
11    "lib": ["es2018"]
12  },
13  "include": ["src/**/*"],
14  "exclude": ["node_modules", "**/*.spec.ts"]
15}

Aplikacja frontendowa dla dashboard zarządzania parkiem

1{
2  "compilerOptions": {
3    "target": "es5",
4    "lib": ["dom", "dom.iterable", "esnext"],
5    "allowJs": true,
6    "skipLibCheck": true,
7    "esModuleInterop": true,
8    "allowSyntheticDefaultImports": true,
9    "strict": true,
10    "forceConsistentCasingInFileNames": true,
11    "module": "esnext",
12    "moduleResolution": "node",
13    "resolveJsonModule": true,
14    "isolatedModules": true,
15    "noEmit": true,
16    "jsx": "react"
17  },
18  "include": ["src"]
19}

Rozszerzanie konfiguracji

W dużym parku dinozaurów mogą istnieć różne strefy z własnymi przepisami bezpieczeństwa, ale wszystkie podlegają ogólnym zasadom. Podobnie, w TypeScript możemy rozszerzać konfiguracje:

1// tsconfig.base.json - główna konfiguracja
2{
3  "compilerOptions": {
4    "target": "es2016",
5    "module": "commonjs",
6    "strict": true
7  }
8}
9
10// tsconfig.backend.json - konfiguracja dla backendu
11{
12  "extends": "./tsconfig.base.json",
13  "compilerOptions": {
14    "outDir": "./dist/backend",
15    "rootDir": "./src/backend"
16  },
17  "include": ["src/backend/**/*"]
18}
19
20// tsconfig.frontend.json - konfiguracja dla frontendu
21{
22  "extends": "./tsconfig.base.json",
23  "compilerOptions": {
24    "outDir": "./dist/frontend",
25    "rootDir": "./src/frontend",
26    "jsx": "react"
27  },
28  "include": ["src/frontend/**/*"]
29}

To jak mapa parku z różnymi strefami, które dzielą wspólne zasady bezpieczeństwa, ale mają też własne, specyficzne wytyczne.

Praktyczny przykład: System monitoringu dla Parku Jurajskiego

Wyobraźmy sobie, że tworzymy nowy system monitoringu dla parku, oto jakiej konfiguracji moglibyśmy użyć:

1{
2  "compilerOptions": {
3    // Wersja ES
4    "target": "es2018",
5    "module": "commonjs",
6    "lib": ["es2018", "dom"],
7    
8    // Struktura projektu
9    "outDir": "./dist",
10    "rootDir": "./src",
11    "baseUrl": ".",
12    "paths": {
13      "@park/*": ["src/park/*"],
14      "@security/*": ["src/security/*"],
15      "@monitoring/*": ["src/monitoring/*"],
16      "@types/*": ["src/types/*"]
17    },
18    
19    // Rygorystyczność
20    "strict": true,
21    "noImplicitAny": true,
22    "strictNullChecks": true,
23    
24    // Zarządzanie modułami
25    "moduleResolution": "node",
26    "esModuleInterop": true,
27    "resolveJsonModule": true,
28    
29    // Narzędzia developerskie
30    "sourceMap": true,
31    "declaration": true,
32    
33    // Dodatkowe reguły
34    "forceConsistentCasingInFileNames": true,
35    "skipLibCheck": true,
36    "noUnusedLocals": true,
37    "noUnusedParameters": true
38  },
39  "include": ["src/**/*"],
40  "exclude": ["node_modules", "dist", "**/*.spec.ts"]
41}

Z tym plikiem konfiguracyjnym, nasz system bezpieczeństwa dla Parku Jurajskiego byłby:

  • Nowoczesny i kompatybilny z aktualnymi standardami (
    es2018
    )
  • Dobrze zorganizowany z jasną strukturą katalogów
  • Rygorystyczny w sprawdzaniu typów, nie pozwalając na potencjalne luki
  • Elastyczny w zarządzaniu modułami i zależnościami
  • Łatwy w debugowaniu i z dobrą dokumentacją typów
  • Wolny od nieużywanych zmiennych i parametrów, które mogłyby prowadzić do zamieszania

Narzędzia pomocnicze

Poza samym plikiem tsconfig.json, warto również skonfigurować narzędzia pomocnicze, które wspierają pracę z TypeScript:

ESLint dla TypeScript

ESLint to jak dodatkowy system nadzoru w parku, który wyłapuje potencjalne zagrożenia:

1// .eslintrc.json
2{
3  "parser": "@typescript-eslint/parser",
4  "plugins": ["@typescript-eslint"],
5  "extends": [
6    "eslint:recommended",
7    "plugin:@typescript-eslint/recommended"
8  ],
9  "rules": {
10    "no-console": "warn",
11    "@typescript-eslint/explicit-function-return-type": "error",
12    "@typescript-eslint/no-explicit-any": "error"
13  }
14}

Prettier dla formatowania kodu

Prettier to jak standard ubierania się i zachowania dla pracowników parku - wszyscy wyglądają i działają spójnie:

1// .prettierrc
2{
3  "semi": true,
4  "trailingComma": "all",
5  "singleQuote": true,
6  "printWidth": 100,
7  "tabWidth": 2
8}

Typowe problemy i rozwiązania

Problem: "Property 'x' does not exist on type 'y'"

Ten błąd to jak system bezpieczeństwa alarmujący, że próbujesz użyć nieistniejącego kodu dostępu do zagrody:

1// Błąd
2const dino = { gatunek: "T-Rex", wiek: 5 };
3console.log(dino.wysokosc); // Error: Property 'wysokosc' does not exist on type '{ gatunek: string; wiek: number; }'.
4
5// Rozwiązanie 1: Dodaj właściwość do typu
6const dino: { gatunek: string; wiek: number; wysokosc?: number } = { 
7  gatunek: "T-Rex", 
8  wiek: 5 
9};
10
11// Rozwiązanie 2: Użyj interfejsu
12interface Dinozaur {
13  gatunek: string;
14  wiek: number;
15  wysokosc?: number;
16}
17const dino: Dinozaur = { gatunek: "T-Rex", wiek: 5 };

Problem: Konfiguracja nie jest stosowana

Czasem, podobnie jak w parku gdy system bezpieczeństwa nie reaguje, konfiguracja TypeScript może nie być właściwie stosowana:

  1. Sprawdź, czy ścieżki w
    include
    i
    exclude
    są poprawne
  2. Upewnij się, że używasz odpowiedniego pliku tsconfig.json
  3. Zrestartuj serwer TypeScript w swoim IDE
1# Sprawdź, które pliki są przetwarzane przez TypeScript
2tsc --listFiles
3
4# Sprawdź, czy kompilator znajduje plik tsconfig.json
5tsc --showConfig

Problem: Brak typów dla biblioteki zewnętrznej

To jak odkrycie, że brakuje dokumentacji dla nowego sprzętu bezpieczeństwa w parku:

1# Spróbuj znaleźć definicje typów dla biblioteki
2npm install --save-dev @types/nazwa-biblioteki
3
4# Jeśli nie istnieją oficjalne typy, stwórz własne
5touch src/types/nazwa-biblioteki.d.ts
1// src/types/nazwa-biblioteki.d.ts
2declare module 'nazwa-biblioteki' {
3  export function funkcja1(param: string): number;
4  export function funkcja2(param: number): string;
5  export const stala: string;
6}

Podsumowanie

Plik tsconfig.json jest jak mapa Parku Jurajskiego – definiuje strefy, poziomy bezpieczeństwa i wytyczne dla wszystkich systemów. Odpowiednia konfiguracja TypeScript zapewnia:

  1. Spójny kod w całym projekcie
  2. Wykrywanie potencjalnych problemów na wczesnym etapie
  3. Lepsze wsparcie narzędzi developerskich
  4. Jasne reguły dla całego zespołu programistów

Tak jak John Hammond nie szczędził kosztów na zabezpieczenia parku, tak i my nie powinniśmy pomijać odpowiedniej konfiguracji TypeScript. To inwestycja, która zwraca się w postaci bardziej stabilnego i bezpiecznego kodu.

W następnej lekcji przyjrzymy się kompilatorowi TypeScript i dowiemy się, jak przekształca on kod TypeScript w JavaScript, podobnie jak naukowcy w laboratorium przekształcają DNA w żywe dinozaury!

Przejdź do CodeWorlds