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.
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 --initTa 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.
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:
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:
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 parkunoImplicitAny 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łaZarzą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łamiesModuleInterop to jak zapewnienie, że starsze i nowsze systemy komunikacji działają razemresolveJsonModule to jak możliwość odczytywania standardowych formularzy raportówDr. 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 takdeclaration to jak rejestr wszystkich gatunków dinozaurówincremental to jak optymalizacja procesu klonowania, aby nie powtarzać tych samych procedurJeś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.
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}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}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.
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:
es2018)Poza samym plikiem tsconfig.json, warto również skonfigurować narzędzia pomocnicze, które wspierają pracę z 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 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}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 };Czasem, podobnie jak w parku gdy system bezpieczeństwa nie reaguje, konfiguracja TypeScript może nie być właściwie stosowana:
include i exclude są poprawne1# Sprawdź, które pliki są przetwarzane przez TypeScript
2tsc --listFiles
3
4# Sprawdź, czy kompilator znajduje plik tsconfig.json
5tsc --showConfigTo 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.ts1// 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}Plik tsconfig.json jest jak mapa Parku Jurajskiego – definiuje strefy, poziomy bezpieczeństwa i wytyczne dla wszystkich systemów. Odpowiednia konfiguracja TypeScript zapewnia:
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!