Opcjonalne właściwości w TypeScript oznaczane są znakiem zapytania (?) po nazwie właściwości. Oznacza to, że właściwość może być albo określona, albo nieobecna w obiekcie. Jest to wygodne przy opisywaniu struktur, gdzie nie wszystkie pola są obowiązkowe.
Przykład:
interface User { id: number; name?: string; } const u1: User = { id: 1 }; // OK const u2: User = { id: 2, name: 'Ivan' }; // OK
Szczegóły:
undefined, ale także całkowicie nieobecna w obiekcie.if (user.name)) nie odróżnia undefined od braku.undefined, i odwoływanie się do metod/właściwości bez sprawdzenia.Aby się zabezpieczyć:
undefined:if (user.name !== undefined) { console.log(user.name.toUpperCase()); }
console.log(user.name?.toUpperCase());
Jeśli obiekt ma opisany interfejs
{ foo?: string }, czy zawsze właściwośćfoomoże być tylko ciągiem lubundefined? Czy można w nim zapisać, na przykład, wartośćnull?
Błędna odpowiedź:
undefined, inne wartości są niedopuszczalne."Prawidłowa odpowiedź:
null, TypeScript to dopuszcza, ale tylko jeśli typ jest rozszerzony do string | null. Domyślnie tylko string lub undefined.interface A { foo?: string } let x: A = { foo: null }; // Błąd!
Historia
W dużym projekcie część obiektów przychodziła z serwera bez niektórych opcjonalnych pól. Programista bezpośrednio wywoływał metody na tych właściwościach (np. toLowerCase()), co prowadziło do błędów w czasie działania, jeśli pole było nieobecne. Aby rozwiązać problem, zespół wdrożył ścisłe kontrole i zasady lintera dotyczące dostępu do opcjonalnych pól.
Historia
W wyrażeniach logicznych pomylono obecność właściwości z jej prawdziwością: if (user.email) nie działało dla pustych ciągów, chociaż właściwość była określona. Pojawił się błąd, z powodu którego niektóre powiadomienia nie były wysyłane do użytkowników.
Historia
Zespół postanowił zapisywać wartość null w opcjonalnej właściwości, myśląc, że to poprawne. TypeScript zgłosił błąd, a aby to obejść, musiano rozszerzyć typ do string | null, co wymagało przemyślenia całej logiki biznesowej dotyczącej tych obiektów.