Tryb strict to opcja "strict": true w tsconfig.json. To jeden przełącznik dla ośmiu flag sprawdzania typów, które wyłapują niejawne any, niesprawdzone null i undefined, niebezpieczne przypisania funkcji oraz niezainicjowane pola klas. W TypeScript 7 strict jest domyślnie włączony. Tak wygląda kod, który przechodzi te sprawdzenia:
Wynik to no user, SyntaxError i 42. Usuń : number, ?. albo sprawdzenie instanceof, a plik przestanie się kompilować.
Jak go włączyć
{
"compilerOptions": {
"strict": true
}
}
Pojedyncze flagi mają pierwszeństwo przed strict, w obie strony. "strict": true, "strictNullChecks": false zostawia wszystko poza sprawdzaniem null, a "strict": false, "noImplicitAny": true włącza tylko tę jedną flagę. strict oznacza też zgodę na sprawdzenia dodane w przyszłych wersjach, bo nowe flagi z rodziny strict dołączają do grupy.
strict w TypeScript nie ma nic wspólnego z dyrektywą "use strict" w JavaScript, która jest trybem działania w czasie wykonania. TypeScript 7 zawsze emituje "use strict" tam, gdzie to potrzebne, a ustawienie alwaysStrict: false to błąd TS5108 (opcję usunięto).
Co wyłapuje każda flaga
| Flaga | Co zgłasza | Błąd |
|---|---|---|
noImplicitAny | parametr lub zmienną, której typ po cichu byłby any | TS7006 Parameter 'x' implicitly has an 'any' type. |
strictNullChecks | użycie wartości, która może być null lub undefined | TS18048 'u' is possibly 'undefined'. |
strictFunctionTypes | przypisanie funkcji, której typ parametru jest węższy niż wymagany | TS2322 |
strictBindCallApply | złe argumenty dla .call, .bind i .apply | TS2345 |
strictPropertyInitialization | pole klasy, któremu nigdy nie przypisano wartości | TS2564 Property 'name' has no initializer and is not definitely assigned in the constructor. |
noImplicitThis | this z niejawnym typem any, na przykład w zagnieżdżonej function | TS2683 |
useUnknownInCatchVariables | użycie zmiennej z catch przed jej zawężeniem (ma typ unknown) | TS18046 'err' is of type 'unknown'. |
strictBuiltinIteratorReturn | traktowanie it.next().value wbudowanego iteratora jak zawsze zdefiniowanego | TS2322 |
Najwięcej kodu zmieniają dwie flagi: noImplicitAny i strictNullChecks. Ten blok celowo łamie obie:
Wypisuje index.ts(2,17): error TS7006: Parameter 'x' implicitly has an 'any' type. oraz index.ts(11,13): error TS18048: 'user' is possibly 'undefined'. Bez strict ten kod się kompiluje, a potem pada w czasie wykonania z TypeError: Cannot read properties of undefined (reading 'name'). Ze strict awaria zamienia się w błąd kompilacji. Poprawki to pierwszy blok na tej stronie.
strictFunctionTypes: po co istnieje
Funkcja, która obsługuje tylko napisy, nie może być użyta tam, gdzie mogą trafić liczby. Poniższe sprawdzenie jest wyciszone przez @ts-expect-error, żeby można było je uruchomić i zobaczyć, przed czym chroni błąd:
Bez komentarza przypisanie to błąd TS2322, Type '(s: string) => void' is not assignable to type 'Handler'., a po nim Types of parameters 's' and 'value' are incompatible. Celowo zostawiono jeden wyjątek: parametry metod zadeklarowanych składnią metody (handle(value: string | number): void wewnątrz interfejsu) wciąż są sprawdzane łagodniej, więc shout dałoby się przypisać do takiej metody bez błędu.
strictPropertyInitialization
Każde pole klasy musi dostać wartość w deklaracji albo w konstruktorze. Są trzy sposoby, żeby to spełnić:
Wynik:
Account {
owner: 'Ada',
balance: 0,
history: [],
lastLogin: undefined,
sessionId: 's-1'
}
Właściwości lastLogin i sessionId istnieją z wartością undefined, bo przy targecie ES2022 pola klas są prawdziwymi polami JavaScriptu. ! usuwa sprawdzenie, nie dodając żadnej ochrony w czasie wykonania, więc lepiej wybierać pozostałe formy. Ta flaga wymaga strictNullChecks: wyłączenie tamtej wyłącza też tę.
Włączanie strict w istniejącym projekcie
Przełączenie dużego projektu na strict naraz może dać setki błędów. Ponieważ strict jest domyślny w TypeScript 7, aktualizacja projektu, którego tsconfig.json nigdy nie wspominał o strict, sama go włącza. Napisz "strict": false, jeśli na czas migracji potrzebujesz starego zachowania. Droga, na której build cały czas przechodzi:
- Dodaj
"strict": truei wyłącz flagi z największą liczbą błędów, zwykle"strictNullChecks": falsei"noImplicitAny": false. - Popraw pozostałe błędy, potem włącz kolejną flagę i powtórz.
- Przy
noImplicitAnywiększość poprawek to adnotacje parametrów. PrzystrictNullChecksdodaj| undefinedtam, gdzie wartości może brakować, a potem obsłuż to przez?.,??albo sprawdzenieif. - Tam, gdzie poprawka musi poczekać, dopisz w linii
// @ts-expect-errorz uzasadnieniem. W przeciwieństwie do@ts-ignorezgłasza on błąd, gdy problem zniknie, więc lista sama się skraca.
Nie wyciszaj błędów hurtowo przez as any albo !: każde takie użycie ukrywa dokładnie ten błąd, do którego wyłapywania dodano flagę.
Przydatne flagi spoza strict
Są osobno, bo odrzucają kod, który często jest poprawny. Wiele projektów i tak je włącza.
| Flaga | Co robi |
|---|---|
noUncheckedIndexedAccess | arr[i] i record[key] mają w typie undefined |
exactOptionalPropertyTypes | debug?: boolean przyjmuje brak klucza, ale nie debug: undefined |
noImplicitReturns | każda ścieżka funkcji zwracającej wartość musi coś zwrócić (TS7030) |
noImplicitOverride | metoda nadpisująca metodę bazową musi mieć override (TS4114) |
noFallthroughCasesInSwitch | niepusty case musi kończyć się break, return albo throw (TS7029) |
noUnusedLocals, noUnusedParameters | nieużywane zmienne i parametry są błędami |
noPropertyAccessFromIndexSignature | klucze z sygnatury indeksu wymagają obj["key"], a nie obj.key |
Najwięcej prawdziwych błędów wyłapuje noUncheckedIndexedAccess. Gdy jest włączona:
const scores = [90, 85];
const d: Record<string, number> = {};
const third: number = scores[2]; // error TS2322: Type 'number | undefined' is not assignable to type 'number'.
const c: number = d["x"]; // same error
const safe = scores[2] ?? 0; // number
for (const s of scores) { // for...of is not affected: s is number
console.log(s);
}
tsc --init w TypeScript 7 włącza w generowanej konfiguracji noUncheckedIndexedAccess i exactOptionalPropertyTypes, obok strict.
Najczęściej zadawane pytania
Co robi tryb strict w TypeScript?
"strict": true włącza grupę ostrzejszych sprawdzeń: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables i strictBuiltinIteratorReturn. Razem nie pozwalają, by any pojawiało się po cichu, i sprawiają, że null oraz undefined stają się częścią systemu typów.
Czy tryb strict jest domyślnie włączony w TypeScript?
W TypeScript 7 tak: strict ma domyślnie wartość true, więc projekt bez ustawienia strict dostaje wszystkie sprawdzenia strict. tsc --init też jawnie zapisuje "strict": true. Żeby z tego zrezygnować, trzeba napisać "strict": false.
Czy mogę wyłączyć jedno sprawdzenie strict, a resztę zostawić?
Tak. Pojedyncze flagi mają pierwszeństwo przed strict: { "strict": true, "strictNullChecks": false } zostawia każde sprawdzenie strict poza sprawdzaniem null. Tak zwykle migruje się duży projekt, flaga po fladze.
Czy tryb strict w TypeScript to to samo co "use strict" w JavaScript?
Nie. "use strict" to tryb działania JavaScriptu, który zmienia zachowanie kodu w czasie wykonania. strict w TypeScript zmienia tylko to, co zgłasza sprawdzanie typów. TypeScript 7 zawsze emituje "use strict" dla wyjścia, które nie jest modułem, a alwaysStrict: false to teraz usunięta opcja.
Czy strict obejmuje noUncheckedIndexedAccess?
Nie. noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitReturns, noImplicitOverride i noFallthroughCasesInSwitch to osobne flagi, które włączasz samodzielnie. tsc --init włącza pierwsze dwie w generowanej konfiguracji.