Adnotacje typów w TypeScript to sposób, w jaki programista może jawnie określić, jakiego rodzaju wartości oczekuje w zmiennych, funkcjach, obiektach, tablicach czy klasach. Dzięki adnotacjom typów kompilator TypeScript wie, jakie dane są przypisane do poszczególnych elementów programu, co umożliwia wcześniejsze wykrywanie błędów i zapewnia lepszą kontrolę nad kodem.
Przykłady adnotacji typów dla zmiennych:
const apples: number = 5;
let speed: string = 'fast';
let hasName: boolean = true;
let nothingMuch: null = null;
let nothing: undefined = undefined;
W powyższych przykładach każda zmienna ma przypisany typ (number
, string
, boolean
, null
, undefined
), co ułatwia przewidywanie, jakie wartości mogą być przechowywane w zmiennych. Takie przypisanie pomaga w uniknięciu błędów typu „niespodziewana wartość” w czasie wykonywania programu.
Adnotacje typów wbudowanych obiektów (np. Date
):
let now: Date = new Date();
Zmienna now
jest typu Date
i oczekuje wartości będącej instancją klasy Date
. Dzięki temu mamy pewność, że now
będzie przechowywać datę i możemy korzystać z metod dostępnych dla tego typu obiektu, takich jak toLocaleDateString()
czy getFullYear()
.
Definicja i podstawy inferencji typów (Type Inference)
Inferencja typów to proces, w którym TypeScript automatycznie określa typ zmiennej, funkcji czy obiektu na podstawie przypisanej do nich wartości. Jeśli nie użyjemy jawnych adnotacji typów, TypeScript spróbuje samodzielnie odgadnąć, z jakim typem ma do czynienia.
Przykład inferencji typów:
let count = 10; // TypeScript automatycznie przypisze typ `number`
let message = "Hello!"; // TypeScript przypisze typ `string`
W powyższych przypadkach kompilator samodzielnie rozpoznaje typ number
i string
na podstawie przypisanych wartości. Dzięki inferencji programista nie musi ręcznie przypisywać typów, co sprawia, że kod staje się bardziej przejrzysty.
Różnice między adnotacjami typów a inferencją typów
- Adnotacje typów (Type Annotations):
- Są dodawane ręcznie przez programistę.
- Przydatne w sytuacjach, gdy typ wartości nie jest jednoznaczny lub kiedy chcemy mieć pełną kontrolę nad typami w kodzie.
- Pomagają w sytuacjach, gdy wartość zmiennej może zmieniać się w zależności od warunków (np.
string
lubnull
).
- Inferencja typów (Type Inference):
- Działa automatycznie, bez konieczności ręcznego określania typu.
- Idealna do prostych przypisań, gdy typ jest oczywisty i jednoznaczny.
- Ułatwia pisanie kodu, zmniejszając ilość deklaracji typów.
Przykłady zastosowania adnotacji i inferencji typów
Adnotacje typów dla zmiennych:
let speed: string = "fast";
let age: number = 25;
Wartości przypisane zmiennym mają jawnie określone typy, co wyraźnie komunikuje ich przeznaczenie.
Inferencja typów dla zmiennych:
let color = "blue"; // Kompilator przypisze typ `string`
let amount = 500; // Kompilator przypisze typ `number`
Adnotacje typów w funkcjach:
const logNumber: (i: number) => void = (i: number) => {
console.log(i);
};
Adnotacje określają, że funkcja logNumber
przyjmuje argument i
typu number
i nie zwraca żadnej wartości (void
).
Inferencja typów w funkcjach:
function greet(name: string) {
return `Hello, ${name}`;
}
TypeScript automatycznie przypisze typ string
dla zwracanej wartości, ponieważ name
ma typ string
.
Zastosowanie adnotacji typów dla obiektów
Adnotacje typów są szczególnie przydatne przy definiowaniu struktury obiektów, co zapewnia przejrzystość i jednoznaczność danych:
let point: { x: number; y: number } = {
x: 10,
y: 20
};
W powyższym przykładzie obiekt point
ma zdefiniowane dwie właściwości: x
i y
typu number
.
Różnica między null
a undefined
null
i undefined
to specjalne typy używane do oznaczenia braku wartości, ale mają różne znaczenie:
null
:
- Oznacza celowy brak wartości.
- Programista musi przypisać
null
jawnie do zmiennej. - Przykład:
let user: string | null = null;
- Zmienna
user
może przyjmować wartośćstring
lubnull
. Użycienull
oznacza, że brak wartości jest świadomym wyborem.
undefined
:
- Oznacza brak przypisanej wartości. Jest to domyślna wartość zmiennej, która została zadeklarowana, ale jeszcze nie została zainicjowana.
- Przykład:
let username: string | undefined;
console.log(username); // undefined
Przykłady użycia null
i undefined
Zmienna z wartością null
:
let currentUser: string | null = "Anna";
currentUser = null; // Użytkownik wylogowany, brak aktywnego użytkownika
console.log(currentUser); // Wydrukuje: null
Zmienna z wartością undefined
:
let pendingUser: string | undefined;
console.log(pendingUser); // Wydrukuje: undefined
Dlaczego przypisujemy undefined = undefined; null = null
?
Przypisanie undefined
do undefined
i null
do null
może wydawać się redundantne, ale ma swoje uzasadnienie:
- Jawne określenie typu:
- Gdy przypisujemy
null
do zmiennejnothingMuch
, jasno komunikujemy, żenothingMuch
jest zmienną, która przechowuje wyłącznienull
i nie może przechowywać żadnej innej wartości. - Przypisanie
undefined
doundefined
wskazuje, że zmienna może przyjmować wartośćundefined
, co jest przydatne, gdy chcemy pokazać, że zmienna jeszcze nie ma przypisanej wartości, ale oczekujemy jej późniejszego zainicjowania.
- Gdy przypisujemy
- Komunikacja w zespole:
- Jawne przypisanie
null
lubundefined
jest sposobem komunikacji między programistami. Wskazuje, że brak wartości jest zamierzony (null
) lub że wartość zmiennej jest jeszcze nieustalona (undefined
).
- Jawne przypisanie
- Eliminacja niejasności:
- Przypisanie
null = null
lubundefined = undefined
eliminuje wszelkie niejasności i pomaga w uniknięciu błędów logicznych, ponieważ wartości te są explicite określone.
- Przypisanie
Kiedy używać null
, a kiedy undefined
?
Używaj null
, gdy:
Chcesz zasygnalizować, że zmienna powinna być pusta, np. w celu wyczyszczenia wartości:
let activeUser: string | null = "Jan";
activeUser = null; // Wylogowanie użytkownika
Używaj undefined
, gdy:
Zmienna jeszcze nie ma przypisanej wartości i oczekujesz jej późniejszego przypisania
let userRole: string | undefined;
userRole = "admin"; // Zainicjowanie zmiennej później w kodzie