null, undefined i bezpieczny dostęp
Brak wyniku to też informacja. Naucz się odróżniać brak od zera i pustego tekstu, zamiast dopisywać wykrzykniki, żeby uciszyć kompilator.
Po tej lekcji potrafisz
- Opiszesz możliwość braku wartości w typie.
- Użyjesz ?. i ?? zgodnie z ich znaczeniem.
- Obsłużysz nieudane wyszukiwanie i wyjaśnisz ryzyko operatora !.
Gracza nie ma w rankingu
Szukasz nicku w tabeli wyników. Co powinien dostać program, jeśli taki gracz nie istnieje? Zero punktów oznacza coś innego niż brak gracza. Zamiast mieszać te sytuacje, pokażemy brak w typie.
Małe kroki, konkretne efekty
Dwa sposoby oznaczania braku
undefined często pojawia się przy brakującym polu lub nieudanym wyszukiwaniu. null bywa celowym oznaczeniem „nie wybrano”. To konwencje — reguły konkretnego programu trzeba określić. W trybie strict nie udajemy, że te wartości są zwykłym tekstem.
function wybranyNick(nick: string | null): string {
if (nick === null) { return "Wybierz gracza"; }
return nick.toUpperCase();
}
console.log(wybranyNick(null));
console.log(wybranyNick("pixel"));
Wybierz gracza
PIXEL
Osobna gałąź dla null pozwala bezpiecznie użyć metody tekstowej w pozostałej części funkcji.
Opcjonalny łańcuch i wartość zastępcza
?. zatrzymuje dostęp, gdy wartość po jego lewej stronie jest null albo undefined, i daje undefined. Operator ?? wybiera prawą stronę tylko przy tych dwóch wartościach. Nie odrzuca zera ani false.
interface Profil { staty?: { punkty: number } }
function punkty(p: Profil): number { return p.staty?.punkty ?? 0; }
console.log(punkty({}));
console.log(punkty({ staty: { punkty: 0 } }));
console.log(punkty({ staty: { punkty: 12 } }));
0
0
12
Tutaj świadomie wyświetlamy 0 również przy braku statystyk. Jeśli musisz odróżniać te sytuacje, zwróć number | undefined zamiast stosować zastępstwo.
Wyszukiwarka wyników
find zwraca pierwszy pasujący element albo undefined. Dwa poprawne komunikaty odróżnią gracza z zerem punktów od osoby spoza rankingu.
interface Gracz { nick: string; punkty: number }
const gracze: Gracz[] = [{ nick: "Ala", punkty: 0 }, { nick: "Pixel", punkty: 15 }];
function wynik(nick: string): string {
const gracz = gracze.find(g => g.nick === nick);
if (gracz === undefined) { return nick + ": brak w rankingu"; }
return gracz.nick + ": " + gracz.punkty + " pkt";
}
console.log(wynik("Ala"));
console.log(wynik("Neo"));
Ala: 0 pkt
Neo: brak w rankingu
Jak program dochodzi do wyniku
- Callback find sprawdza nick każdego elementu do pierwszego dopasowania.
- Wynik ma typ Gracz | undefined.
- Warunek rozpoznaje brak obiektu, a nie fałszywość jego punktów.
- Po return w gałęzi braku gracz jest już pewnym obiektem.
Zanim przejdziesz dalej
Dlaczego if (!gracz?.punkty) jest złym testem istnienia gracza?
Sprawdź swoje rozumowanie
Da true również dla istniejącego gracza z zerem punktów. Sprawdzaj istnienie obiektu, a nie prawdziwość liczby.
Zmień kod i zobacz, co się stanie
Wykrzyknik nie jest sprawdzeniem
Operator ! po wartości usuwa null i undefined tylko z widoku kompilatora. Nie wstawia żadnego warunku. Bezpieczniejszy kod pokazuje, co zrobić po pustym wyszukiwaniu.
const wyniki = [10, 20];
const znaleziony = wyniki.find(n => n > 100);
console.log(znaleziony?.toFixed(1) ?? "Nie znaleziono");
// znaleziony!.toFixed(1) spowodowałoby błąd w czasie wykonania.
Nie znaleziono
Zmień próg na 15: zobaczysz 20.0. ?. chroni przed brakiem, ale nie przechwytuje wyjątków rzuconych przez samą wywołaną metodę.
Gdy wynik zaskakuje
| Pomyłka | Co się dzieje i jak to poprawić |
|---|---|
| || zamiast ?? przy liczbach | Zero jest fałszywe dla ||, ale często jest poprawną wartością. |
| ?. traktowane jak naprawa danych | Operator daje undefined. Nadal musisz ustalić, jak program reaguje na brak. |
| ! zamiast warunku | Wykrzyknik nie zapobiega błędowi wykonania. |
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.
Funkcja ma przyjmować number | undefined. Brak daje 50, a 0 ma pozostać 0.
Mała podpowiedź
Użyj ??, nie ||.
Przykładowe rozwiązanie z wyjaśnieniem
function glosnosc(n: number | undefined): number { return n ?? 50; }
console.log(glosnosc(undefined), glosnosc(0));
50 0
Wartość zastępcza nie odbiera możliwości wyciszenia dźwięku.
Zwróć tekst ostatniego elementu tablicy albo „Brak rund”. Sprawdź [3, 8] oraz [].
Mała podpowiedź
at(-1) i opcjonalne toString.
Przykładowe rozwiązanie z wyjaśnieniem
function ostatni(rundy: number[]): string {
return rundy.at(-1)?.toString() ?? "Brak rund";
}
console.log(ostatni([3, 8]));
console.log(ostatni([]));
8
Brak rund
at może zwrócić undefined, także gdy tablica ma typ number[].
Profil może nie mieć adresu, a adres miasta. Zwróć miasto lub „Nie podano”. Sprawdź obie sytuacje.
Mała podpowiedź
Pytajnik przy polu w typie i ?. przy odczycie.
Przykładowe rozwiązanie z wyjaśnieniem
interface Profil { adres?: { miasto?: string } }
function miasto(p: Profil): string { return p.adres?.miasto ?? "Nie podano"; }
console.log(miasto({}));
console.log(miasto({ adres: { miasto: "Gdynia" } }));
Nie podano
Gdynia
Brak adresu nie prowadzi do odczytu pola z undefined.
Pusta lista ocen ma zwracać null. W raporcie wypisz „Brak ocen”; [4, 5] ma dać 4.50. Oddziel funkcję obliczającą od raportu.
Mała podpowiedź
number | null opisuje dwie możliwości wyniku.
Przykładowe rozwiązanie z wyjaśnieniem
function srednia(oceny: number[]): number | null {
if (oceny.length === 0) { return null; }
return oceny.reduce((s, n) => s + n, 0) / oceny.length;
}
// reduce dodaje elementy do sumy zaczynającej od 0; szerzej w lekcji 23.
function raport(oceny: number[]): string { return srednia(oceny)?.toFixed(2) ?? "Brak ocen"; }
console.log(raport([]));
console.log(raport([4, 5]));
Brak ocen
4.50
Brak danych nie jest sztuczną oceną zero.
Co zabierasz do następnej lekcji
- Brak wartości warto pokazać w typie.
- ?. daje bezpieczny dostęp przy null i undefined; ?? dobiera zastępstwo.
- ! jest zapewnieniem dla kompilatora, a nie ochroną podczas działania.