TypeScript strict — dlaczego i jak
Frontend ZEUS to Next.js 15 + TypeScript. TypeScript ma sens tylko wtedy, gdy działa w trybie strict — inaczej dostajesz iluzję bezpieczeństwa. Ta lekcja pokazuje, dlaczego strict jest u nas obowiązkowy i jak z nim pracować.
Czym jest strict
strict: true w tsconfig.json włącza zestaw rygorystycznych kontroli naraz —
m.in. strictNullChecks, noImplicitAny, strictFunctionTypes. Bez tego null
i undefined przechodzą wszędzie, a any mnoży się po cichu.
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"skipLibCheck": true
}
}
Standard ProfessNet: każdy projekt frontu ma
strict: trueplusnoUncheckedIndexedAccess. To ostatnie wymusza obsługę przypadku, gdy indeks tablicy zwracaundefined.
null i undefined są jawne
W strict string nie może być null. Jeśli wartość bywa pusta, typ to mówi.
// typ jawnie dopuszcza brak wartości
function findProbe(id: string): Probe | undefined {
return probes.find((p) => p.id === id);
}
const probe = findProbe(id);
probe.host; // błąd — probe może być undefined
if (probe) {
probe.host; // OK — zawężenie typu
}
Walka z any
any wyłącza TypeScript. Zamiast niego używaj unknown i zawężaj typ jawnie.
// źle — any przepuszcza wszystko
function parse(raw: any) {
return raw.data.items; // brak żadnej kontroli
}
// dobrze — unknown wymusza sprawdzenie
function parse(raw: unknown): Item[] {
const data = ScanResultSchema.parse(raw); // np. zod
return data.items;
}
Standard ProfessNet:
anyjest zabronione w nowym kodzie (reguła ESLint@typescript-eslint/no-explicit-any). Granice z zewnętrznym światem (API,localStorage) walidujemy schematem (zod) i dostajemy bezpieczny typ.
Typy z jednego źródła prawdy
Nie przepisujemy typów ręcznie. Wyprowadzamy je ze schematu albo z backendu.
import { z } from "zod";
export const ProbeSchema = z.object({
id: z.string(),
host: z.string(),
forest: z.string(),
});
export type Probe = z.infer<typeof ProbeSchema>; // typ = schema
| Konstrukcja | Zamiast |
|---|---|
unknown + walidacja | any |
| `X | undefined` |
z.infer<...> | ręcznie pisany interfejs |
as const | luźny string/number |
Sprawdzanie typów w CI
tsc --noEmit # sam type-check, bez budowania
Komendę odpalamy w CI obok ESLint. Czerwony tsc blokuje merge.
Wskazówka: nie używaj
// @ts-ignore. Jeśli musisz, to// @ts-expect-errorz komentarzem — zniknie automatycznie, gdy błąd przestanie występować.
Strict to różnica między „kompiluje się" a „działa". Włączony od pierwszego dnia projektu kosztuje niewiele; włączony później to bolesny refaktor. Dlatego w ZEUS-ie jest standardem od startu.