Kurs JavaScript i TypeScript · Moduł 6: Podstawy TypeScript
Konfiguracja TypeScript i narzędzia
W tej lekcji7
W Parku Jurajskim nawet najlepszy system genetyczny jest bezużyteczny bez właściwej kalibracji sprzętu laboratoryjnego. Tak samo TypeScript bez odpowiedniej konfiguracji nie wykorzysta swojego pełnego potencjału. Plik tsconfig.json to Twój panel sterowania - definiuje, jak kompilator TypeScript interpretuje i transformuje Twój kod.
tsconfig.json - centrum dowodzenia
Każdy projekt TypeScript zaczyna się od pliku tsconfig.json w katalogu głównym. To plik JSON definiujący opcje kompilatora, które pliki mają być kompilowane i jak ma wyglądać wynik:
1{
2 "compilerOptions": {
3 "target": "ES2020",
4 "module": "ESNext",
5 "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 "outDir": "./dist",
7 "rootDir": "./src",
8 "strict": true,
9 "esModuleInterop": true,
10 "skipLibCheck": true,
11 "forceConsistentCasingInFileNames": true
12 },
13 "include": ["src/**/*"],
14 "exclude": ["node_modules", "dist"]
15}Kluczowe opcje kompilatora
Target - wersja JavaScript na wyjściu:
ES5- kompatybilność ze starszymi przeglądarkamiES2020- nowoczesne środowiska (nullish coalescing, optional chaining)ESNext- najnowsze funkcje
Module - system modułów:
CommonJS- Node.js (require/module.exports)ESNext- moduły ES (import/export)NodeNext- Node.js z obsługą ESM
Lib - jakie API są dostępne:
DOM- API przeglądarki (document, window)ES2020- metody jakPromise.allSettled,BigIntWebWorker- API Web Workers
Strict Mode - maksymalne bezpieczeństwo
Flaga strict: true włącza wszystkie rygorystyczne sprawdzenia jednocześnie. To jak włączenie pełnych zabezpieczeń w Parku Jurajskim - żaden dinozaur nie wymknie się z zagrody:
1// strict: true włącza WSZYSTKIE poniższe:
2{
3 "strictNullChecks": true, // null/undefined muszą być obsłużone
4 "strictFunctionTypes": true, // ścisłe typowanie parametrów funkcji
5 "strictBindCallApply": true, // ścisłe typowanie bind/call/apply
6 "strictPropertyInitialization": true, // właściwości muszą być zainicjalizowane
7 "noImplicitAny": true, // zakaz niejawnego any
8 "noImplicitThis": true, // this musi mieć typ
9 "alwaysStrict": true, // "use strict" w każdym pliku
10 "useUnknownInCatchVariables": true // catch(e) to unknown, nie any
11}Przykład różnicy z strictNullChecks:
1// BEZ strictNullChecks - błąd w runtime!
2function getDinoName(id: string): string {
3 const dino = dinosaurs.find(d => d.id === id);
4 return dino.name; // Runtime error: Cannot read property 'name' of undefined
5}
6
7// Z strictNullChecks - TypeScript wymusza obsługę null
8function getDinoName(id: string): string | undefined {
9 const dino = dinosaurs.find(d => d.id === id);
10 return dino?.name; // Bezpieczne - zwraca undefined jeśli nie znaleziono
11}Path Aliases - skróty nawigacyjne
W dużych projektach importy mogą stać się nieczytelne. Path aliases pozwalają tworzyć skróty:
1{
2 "compilerOptions": {
3 "baseUrl": ".",
4 "paths": {
5 "@models/*": ["src/models/*"],
6 "@utils/*": ["src/utils/*"],
7 "@services/*": ["src/services/*"],
8 "@config": ["src/config/index.ts"]
9 }
10 }
11}Zamiast:
1import { Dinosaur } from '../../../models/dinosaur';
2import { formatDate } from '../../utils/helpers';Piszesz:
1import { Dinosaur } from '@models/dinosaur';
2import { formatDate } from '@utils/helpers';Declaration Files (.d.ts)
Pliki deklaracji opisują typy dla kodu JavaScript. Mają rozszerzenie .d.ts i nie zawierają implementacji - tylko sygnatury typów:
1// dinosaur.d.ts - deklaracja typów
2declare interface IDinosaur {
3 id: string;
4 name: string;
5 species: string;
6 dangerLevel: 1 | 2 | 3 | 4 | 5;
7}
8
9declare function findDinosaur(id: string): IDinosaur | null;
10declare const PARK_NAME: string;
11
12// Deklaracja modułu dla biblioteki JS bez typów
13declare module 'dino-tracker' {
14 export function trackPosition(id: string): [number, number];
15 export function getStatus(id: string): 'active' | 'sleeping' | 'escaped';
16}Trzy rodzaje plików deklaracji:
- Automatyczne - TypeScript generuje je z flagą
declaration: true - Ręczne - piszesz sam dla kodu JS bez typów
- DefinitelyTyped - społecznościowe typy dla popularnych bibliotek
DefinitelyTyped (@types/*)
Wiele bibliotek JavaScript nie ma wbudowanych typów. Repozytorium DefinitelyTyped zawiera typy tworzone przez społeczność:
1# Instalacja typów dla popularnych bibliotek
2npm install --save-dev @types/node
3npm install --save-dev @types/express
4npm install --save-dev @types/lodash
5npm install --save-dev @types/jestTypeScript automatycznie rozpoznaje pakiety @types/* - nie musisz ich importować. Jeśli biblioteka ma wbudowane typy (jak axios czy date-fns), nie potrzebujesz osobnego pakietu @types.
Opcja typeRoots w tsconfig kontroluje, skąd TypeScript ładuje typy:
1{
2 "compilerOptions": {
3 "typeRoots": ["./node_modules/@types", "./src/types"]
4 }
5}ESLint z TypeScript
TypeScript ma własne sprawdzenia typów, ale ESLint z pluginem @typescript-eslint dodaje reguły stylistyczne i zaawansowane analizy:
1{
2 "parser": "@typescript-eslint/parser",
3 "plugins": ["@typescript-eslint"],
4 "extends": [
5 "eslint:recommended",
6 "plugin:@typescript-eslint/recommended",
7 "plugin:@typescript-eslint/recommended-requiring-type-checking"
8 ],
9 "parserOptions": {
10 "project": "./tsconfig.json"
11 },
12 "rules": {
13 "@typescript-eslint/no-explicit-any": "warn",
14 "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
15 "@typescript-eslint/prefer-nullish-coalescing": "error",
16 "@typescript-eslint/prefer-optional-chain": "error"
17 }
18}Najważniejsze reguły @typescript-eslint:
no-explicit-any- ostrzega przed użyciemanyno-unused-vars- wykrywa nieużywane zmienne (z obsługą TypeScript)prefer-nullish-coalescing- preferuj??zamiast||prefer-optional-chain- preferuja?.bzamiasta && a.bstrict-boolean-expressions- zabrania niejawnych konwersji boolean
Opcje jakości kodu
Dodatkowe flagi kompilatora pomagające utrzymać jakość kodu:
1{
2 "compilerOptions": {
3 "noUnusedLocals": true, // błąd przy nieużywanych zmiennych
4 "noUnusedParameters": true, // błąd przy nieużywanych parametrach
5 "noImplicitReturns": true, // każda ścieżka musi zwracać wartość
6 "noFallthroughCasesInSwitch": true, // wymusza break w switch
7 "noUncheckedIndexedAccess": true, // arr[i] to T | undefined
8 "exactOptionalPropertyTypes": true // undefined !== pominięcie pola
9 }
10}Opcja noUncheckedIndexedAccess jest szczególnie przydatna - zabezpiecza przed błędami indeksowania:
1const dinos = ["T-Rex", "Raptor", "Triceratops"];
2
3// BEZ noUncheckedIndexedAccess
4const first: string = dinos[0]; // OK, ale dinos[100] też byłoby "string"!
5
6// Z noUncheckedIndexedAccess
7const first: string | undefined = dinos[0]; // TypeScript wymusza sprawdzenie
8if (first) {
9 console.log(first.toUpperCase()); // Bezpieczne
10}Kod do tej lekcji: index.ts
1// Konfiguracja TypeScript - Laboratorium Parku Jurajskiego
2
3// === 1. STRICT MODE W AKCJI ===
4
5// strictNullChecks - wymusza obsluge null/undefined
6interface IDinosaur {
7 id: string;
8 name: string;
9 species: string;
10 dangerLevel: 1 | 2 | 3 | 4 | 5;
11}
12
13const dinosaurs: IDinosaur[] = [
14 { id: "001", name: "Rexy", species: "T-Rex", dangerLevel: 5 },
15 { id: "002", name: "Blue", species: "Velociraptor", dangerLevel: 4 },
16 { id: "003", name: "Bumpy", species: "Ankylosaurus", dangerLevel: 2 },
17];
18
19// Bezpieczne wyszukiwanie z obsluga undefined
20function findDino(id: string): IDinosaur | undefined {
21 return dinosaurs.find(d => d.id === id);
22}
23
24const dino = findDino("001");
25if (dino) {
26 console.log("Znaleziono:", dino.name, "- poziom zagrozenia:", dino.dangerLevel);
27} else {
28 console.log("Nie znaleziono dinozaura");
29}
30
31// === 2. PATH ALIASES (symulacja) ===
32// W prawdziwym projekcie:
33// import { Dinosaur } from '@models/dinosaur';
34// import { formatDate } from '@utils/helpers';
35// Zamiast: import { Dinosaur } from '../../../models/dinosaur';
36
37// === 3. DECLARATION FILES (.d.ts) ===
38// Symulacja deklaracji typow dla biblioteki JS
39
40// Tak wygladalby plik dino-tracker.d.ts:
41// declare module 'dino-tracker' {
42// export function trackPosition(id: string): [number, number];
43// export function getStatus(id: string): DinoStatus;
44// }
45
46// Uzywamy typow tak, jakby istniala biblioteka:
47type DinoStatus = "active" | "sleeping" | "escaped";
48
49function getStatus(id: string): DinoStatus {
50 const dino = findDino(id);
51 if (!dino) return "escaped";
52 return dino.dangerLevel >= 4 ? "active" : "sleeping";
53}
54
55console.log("Status Rexy:", getStatus("001"));
56console.log("Status Blue:", getStatus("002"));
57
58// === 4. noUncheckedIndexedAccess ===
59const species = ["T-Rex", "Raptor", "Triceratops"];
60
61// Z noUncheckedIndexedAccess: species[0] to string | undefined
62const first = species[0];
63if (first !== undefined) {
64 console.log("Pierwszy gatunek:", first.toUpperCase());
65}
66
67// === 5. DEFINITELYTYPED ===
68// Instalacja typow:
69// npm install --save-dev @types/node @types/express @types/lodash
70// TypeScript automatycznie je rozpoznaje
71
72// === 6. ESLINT Z TYPESCRIPT ===
73// Przyklady regul @typescript-eslint:
74
75// prefer-nullish-coalescing: uzywaj ?? zamiast ||
76const parkName: string | null = null;
77const displayName = parkName ?? "Jurassic Park"; // lepsze niz ||
78console.log("Park:", displayName);
79
80// prefer-optional-chain: uzywaj ?. zamiast &&
81interface ParkConfig {
82 security?: {
83 fences?: {
84 voltage?: number;
85 };
86 };
87}
88
89const config: ParkConfig = { security: { fences: { voltage: 10000 } } };
90const voltage = config.security?.fences?.voltage; // lepsze niz config && config.security && ...
91console.log("Napiecie ogrodzenia:", voltage, "V");
92
93// noImplicitReturns: kazda sciezka musi zwracac wartosc
94function classifyThreat(level: number): string {
95 if (level >= 4) return "WYSOKIE ZAGROZENIE";
96 if (level >= 2) return "SREDNIE ZAGROZENIE";
97 return "NISKIE ZAGROZENIE"; // wymagane przez noImplicitReturns
98}
99
100console.log("Klasyfikacja (5):", classifyThreat(5));
101console.log("Klasyfikacja (1):", classifyThreat(1));Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Którą z poniższych flag NIE włącza opcja "strict": true w tsconfig.json?
2. Jaka jest rola plików .d.ts (declaration files) w TypeScript?
To 2 z 4 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Edytor kodu
Napraw problemy ze strict mode: strictNullChecks, noUncheckedIndexedAccess, noImplicitReturns i skonfiguruj path aliases.
- Edytor kodu
Napisz interfejs SecurityEvent, zaimplementuj checkPerimeter i logEvent, oraz stwórz typ DinoSize z funkcją classifyBySize.
- Układanie w pionie
Uporządkuj opcje tsconfig od najważniejszych (włączaj najpierw) do zaawansowanych:
- Klikanie w kolejności
Ułóż elementy konfiguracji path alias w tsconfig.json:
- Układanie w pionie
Uporządkuj kroki tworzenia nowego projektu TypeScript: