any, unknown, never i asercje
Kompilator pomaga tak długo, jak długo dostaje prawdziwe informacje. Sprawdź, kiedy przyznać „jeszcze nie wiem”, a kiedy opisać sytuację niemożliwą.
Po tej lekcji potrafisz
- Wyjaśnisz różnicę między any i unknown.
- Sprawdzisz nieznaną wartość przed użyciem.
- Rozpoznasz zastosowania never i ograniczenia asercji as.
Paczka danych bez etykiety
Ktoś przekazuje wynik ankiety, ale nie wiesz jeszcze, czy jest liczbą, tekstem czy obiektem. any pozwala zachowywać się tak, jakby wszystko było dozwolone. unknown wymaga otwarcia paczki i sprawdzenia zawartości.
Małe kroki, konkretne efekty
unknown wymusza pytanie o wartość
Do unknown można przypisać dowolną wartość, lecz nie można na ślepo wywoływać jej metod. any wyłącza wiele zabezpieczeń i łatwo przenosi tę niepewność do kolejnych zmiennych.
function pokaz(dane: unknown): string {
if (typeof dane === "string") { return dane.trim(); }
if (typeof dane === "number") { return dane.toFixed(1); }
return "Nieobsługiwany rodzaj danych";
}
console.log(pokaz(" Ala "));
console.log(pokaz(3));
console.log(pokaz(null));
Ala
3.0
Nieobsługiwany rodzaj danych
Po sprawdzeniu typeof nie potrzebujemy as. Kompilator zna już typ w odpowiedniej gałęzi.
as nie konwertuje
Asercja mówi kompilatorowi, jak ma traktować wyrażenie. Nie zamienia tekstu na liczbę i nie sprawdza pól obiektu. Do rzeczywistej konwersji potrzebna jest operacja taka jak Number.
const nieznane: unknown = "42";
const zapewnienie = nieznane as number;
console.log(typeof zapewnienie);
console.log(Number(nieznane) + 1);
string
43
Mimo typu number wpisanego przez as, działający program nadal ma tekst. Podwójna asercja przez unknown nie naprawia danych — tylko obchodzi sprawdzanie.
Odczyt punktów z nieznanej wartości
Przyjmujemy wyłącznie skończone, nieujemne liczby całkowite. Typ number obejmuje także ułamki, NaN i Infinity, więc sam typeof to za mało.
function odczytajPunkty(dane: unknown): number | null {
if (typeof dane !== "number") { return null; }
if (!Number.isFinite(dane) || !Number.isInteger(dane) || dane < 0) { return null; }
return dane;
}
const proby: unknown[] = [12, "12", -1, 1.5, NaN, Infinity];
for (const proba of proby) {
console.log(odczytajPunkty(proba) ?? "Błędne dane");
}
12
Błędne dane
Błędne dane
Błędne dane
Błędne dane
Błędne dane
Jak program dochodzi do wyniku
- unknown[] pozwala przygotować różne rodzaje danych do sprawdzenia.
- Pierwszy warunek odrzuca wszystko poza liczbami.
- Pozostałe warunki sprawdzają reguły gry. Kompilator sam nie odgadnie tych wymagań.
- null sygnalizuje odrzucenie. Nie mylimy go z prawidłowym zerem.
Zanim przejdziesz dalej
Czy „12” zostanie zamienione na 12?
Sprawdź swoje rozumowanie
Nie. Ta funkcja waliduje, ale nie konwertuje. Dzięki temu dane o złym rodzaju nie są po cichu akceptowane.
Zmień kod i zobacz, co się stanie
never pilnuje wszystkich wariantów
never opisuje wartość, która nie powinna móc wystąpić. Po obsłużeniu wszystkich wariantów unii nie zostaje żaden. Funkcja z throw nigdy nie wraca normalnie; szczegóły wyjątków poznasz w lekcji 26.
type Tryb = "solo" | "duet";
function niemozliwe(x: never): never { throw new Error("Nieznany tryb: " + x); }
function limit(tryb: Tryb): number {
switch (tryb) {
case "solo": return 1;
case "duet": return 2;
default: return niemozliwe(tryb);
}
}
console.log(limit("solo"), limit("duet"));
1 2
Dopisz „squad” do Tryb bez nowego case. Kompilator zgłosi, że do never przekazujesz nieobsłużony wariant. void oznacza brak użytecznego wyniku, a never — brak normalnego zakończenia z wynikiem.
Gdy wynik zaskakuje
| Pomyłka | Co się dzieje i jak to poprawić |
|---|---|
| any jako lekarstwo na czerwone podkreślenia | Najpierw ustal model danych. any może ukryć faktyczny błąd. |
| as traktowane jak walidacja | Asercja nie tworzy warunków wykonywanych przez program. |
| typeof n === „number” jako pełna kontrola | NaN i Infinity też mają ten typ. Reguły dziedziny sprawdzaj osobno. |
throw w strażniku typu
Instrukcja throw przerywa program i zgłasza błąd. Używamy jej tu jako najkrótszej
reakcji na dane, które nie przeszły sprawdzenia. Jak taki błąd przechwycić i zareagować zamiast
kończyć program, pokazuje lekcja 26.
Teraz Twoja kolej
Rozwiązanie jest jedną z możliwości. Zanim je odkryjesz, uruchom własną wersję dla podanych danych i przynajmniej jednego przypadku brzegowego.
Przyjmij unknown, zwróć wielkie litery dla tekstu, a dla reszty „Niepoprawny nick”.
Mała podpowiedź
typeof przed toUpperCase.
Przykładowe rozwiązanie z wyjaśnieniem
function nick(x: unknown): string { return typeof x === "string" ? x.toUpperCase() : "Niepoprawny nick"; }
console.log(nick("pixel"));
console.log(nick(12));
PIXEL
Niepoprawny nick
Nie trzeba niczego rzutować.
Akceptuj tylko całkowitą liczbę uczestników 1–16. Sprawdź 0, 1, 16, 17, „4” i 2.5.
Mała podpowiedź
Po typeof dodaj Number.isInteger i zakres.
Przykładowe rozwiązanie z wyjaśnieniem
function poprawnaLiczba(x: unknown): boolean {
return typeof x === "number" && Number.isInteger(x) && x >= 1 && x <= 16;
}
for (const x of [0, 1, 16, 17, "4", 2.5]) { console.log(poprawnaLiczba(x)); }
false
true
true
false
false
false
Granice należą do poprawnego zakresu, ułamki nie.
Wykaż, że as number nie zmienia tekstu „7”. Wypisz typeof po asercji i po Number.
Mała podpowiedź
Wartość startowa unknown pozwala napisać asercję — nie oznacza to, że jest prawdziwa.
Przykładowe rozwiązanie z wyjaśnieniem
const dane: unknown = "7";
const a = dane as number;
const b = Number(dane);
console.log(typeof a, typeof b);
string number
Typ statyczny i rodzaj wartości podczas wykonania mogą się rozminąć po nieprawdziwej asercji.
Obsłuż „nowe”, „w_toku”, „gotowe” i dodaj kontrolę never. Potem dopisz nowy status i sprawdź błąd kompilatora.
Mała podpowiedź
W default przekaż status do funkcji przyjmującej never.
Przykładowe rozwiązanie z wyjaśnieniem
type Status = "nowe" | "w_toku" | "gotowe";
function brak(x: never): never { throw new Error(String(x)); }
function opis(s: Status): string {
switch (s) {
case "nowe": return "Czeka";
case "w_toku": return "Praca trwa";
case "gotowe": return "Zrobione";
default: return brak(s);
}
}
console.log(opis("gotowe"));
Zrobione
Zmiana modelu wymusi uzupełnienie zależnej funkcji.
Co zabierasz do następnej lekcji
- unknown przechowuje nieznane dane bez rezygnowania z kontroli.
- as nie konwertuje i nie sprawdza wartości.
- never pomaga wykryć nieobsłużony wariant.