Zmienne i typy podstawowe

Trzy typy — liczba, tekst i wartość logiczna — wystarczą, żeby opisać większość danych w programie. W tej lekcji uczysz się je deklarować, chronić przed zmianą i bezpiecznie zamieniać jedne na drugie.

TypeScript let / const number · string · boolean 45 min

Praca w konsoli — wspólne zasady kursu

Środowisko: TypeScript 6.0 i Node.js 24 LTS (co najmniej 24.15.0). Każdy pełny przykład uruchamiaj osobno w src/index.ts. Bloki opisane jako celowy błąd służą do odczytania komunikatu kompilatora; nie powinny się uruchomić. Bloki JavaScript pokazują zachowanie JS, a fragmenty są oznaczone osobno. Celem kursu jest składnia TypeScriptu przed nauką Angulara

CEL LEKCJI

Czego się dziś nauczysz

  • Zadeklarujesz zmienną z jawnym typem i bez niego
  • Wybierzesz świadomie między let a const
  • Opiszesz różnicę między liczbą 7 a tekstem "7"
  • Zamienisz tekst na liczbę i sprawdzisz, czy operacja się udała
  • Wyjaśnisz, dlaczego var nie pojawi się w tym kursie
TEORIA

Jak zadeklarować zmienną

Zmienna to nazwane miejsce w pamięci, w którym program przechowuje wartość. W TypeScripcie deklaracja ma zawsze ten sam układ:

schemat deklaracji
  let   punkty   :   number   =   0 ;
  │       │           │           │
  │       │           │           └─ wartość początkowa
  │       │           └───────────── typ (opcjonalny)
  │       └───────────────────────── nazwa
  └───────────────────────────────── słowo kluczowe: let albo const
przykłady
let punkty: number = 0;
let nick: string = "Karol";
let zalogowany: boolean = false;

const PODATEK: number = 0.23;
const SZKOLA: string = "ZSMI Lębork";

Zasady nazywania zmiennych

  • Nazwa może zawierać litery, cyfry oraz znaki _ i $, ale nie może zaczynać się od cyfry.
  • Wielkość liter ma znaczenie: punkty i Punkty to dwie różne zmienne.
  • Przyjęty zwyczaj to camelCase: liczbaUczniow, sredniaOcen.
  • Stałe konfiguracyjne pisze się często wersalikami: MAX_PUNKTOW.
  • Nazwa ma mówić, co zawiera. x i dane2 to nazwy, których nie zrozumiesz za tydzień.

Polskie znaki w nazwach

Technicznie średnia zadziała, ale w praktyce nazwy pisze się bez ogonków — unika się kłopotów z kodowaniem plików i konsolą Windows. Komentarze i teksty wypisywane użytkownikowi piszemy oczywiście normalnie, po polsku.

DECYZJA

let czy const?

Różnica jest jedna: wartość zmiennej let można później podmienić, a const — nie.

Celowy błąd TypeScript — znajdź i popraw przed uruchomieniem
let zycia: number = 3;
zycia = zycia - 1;        // OK — 2
console.log(zycia);

const nazwaGry: string = "Snake";
nazwaGry = "Tetris";      // Błąd TS2588: Cannot assign to 'nazwaGry'
                          // because it is a constant.

Zasada praktyczna, którą stosują zawodowi programiści: zaczynaj od const. Dopiero gdy okaże się, że wartość musi się zmieniać, zmień deklarację na let. Dzięki temu, czytając kod, od razu widzisz, które wartości są ustalone raz na zawsze, a które trzeba śledzić.

A co z var?

W starszym kodzie JavaScript zobaczysz jeszcze var. Ma ono nietypowy zasięg — zmienna „wycieka” poza blok, w którym powstała:

Celowy błąd TypeScript — znajdź i popraw przed uruchomieniem
if (true) {
  var stary = "widoczny na zewnątrz";
  let nowy = "widoczny tylko tutaj";
}

console.log(stary);   // działa — i o to właśnie chodzi z var
console.log(nowy);    // Błąd TS2304: Cannot find name 'nowy'.

To źródło trudnych do wytropienia pomyłek, dlatego w tym kursie var nie użyjemy ani razu. Jeśli zobaczysz je w cudzym kodzie, wiesz, że pochodzi sprzed 2015 roku.

TEORIA

Trzy typy, na których stoi wszystko

TypDo czego służyPrzykładowe wartości
number Wszystkie liczby — całkowite i z częścią dziesiętną, dodatnie i ujemne 0, 42, -7, 3.14, 1e6, 0xFF
string Tekst dowolnej długości, także pusty "Ala", 'x', `wynik`, ""
boolean Odpowiedź na pytanie tak/nie true, false

W TypeScripcie nie ma osobnego int i double

Do zwykłych obliczeń używamy number: obsługuje liczby całkowite i ułamkowe. 7 / 2 daje 3.5; Math.trunc(7 / 2) odrzuca ułamek. Osobny bigint dotyczy liczb całkowitych i ma inne reguły — na razie nie jest potrzebny w naszych zadaniach.

Apostrofy, cudzysłowy i backticki

Tekst możesz zapisać na trzy sposoby. Pierwsze dwa są równoważne, trzeci ma dodatkową moc:

src/index.ts
const a: string = "cudzysłów";
const b: string = 'apostrof';
const c: string = `backtick`;   // klawisz obok lewego Shifta

const imie: string = "Zosia";
const punkty: number = 87;

// sklejanie plusem — czytelne przy dwóch elementach
console.log("Uczeń " + imie + " zdobył " + punkty + " pkt");

// szablon w backtickach — czytelniejszy przy większej liczbie
console.log(`Uczeń ${imie} zdobył ${punkty} pkt`);

Wewnątrz backticków zapis ${…} wstawia wartość zmiennej albo wynik obliczenia. Ten sposób poznamy dokładniej w lekcji 5.

MECHANIZM

Wnioskowanie typu — kiedy typu nie trzeba pisać

TypeScript potrafi sam odgadnąć typ z wartości początkowej. Obie linijki poniżej znaczą dokładnie to samo:

Celowy błąd TypeScript — znajdź i popraw przed uruchomieniem
let wiek: number = 18;   // typ zapisany jawnie
let wiek2 = 18;          // typ wywnioskowany — też number

wiek2 = 19;              // OK
wiek2 = "dziewiętnaście"; // Błąd TS2322 — typ został ustalony przy deklaracji

Zwróć uwagę: brak zapisanego typu nie oznacza, że zmienna przyjmie cokolwiek. Typ został ustalony w momencie deklaracji i już się nie zmieni.

Kiedy pisać typ, a kiedy odpuścić

Pomiń, gdy wartość mówi sama za siebie

const cena = 19.99; — każdy widzi, że to liczba. Dopisywanie : number tylko zaśmieca kod.

Napisz, gdy zaczynasz od pustego

Przy deklaracji bez wartości, np. let wynik: string;, jawny typ określa planowany rodzaj danych. Przy let wynik = ""; kompilator już potrafi wywnioskować string z pustego tekstu.

Zawsze przy parametrach funkcji

Przy zwykłej deklaracji funkcji zapisujemy typy parametrów. W callbackach kompilator często wywnioskuje je z kontekstu — zobaczysz to w lekcji 13.

Napisz, gdy chcesz coś wymusić

Kiedy zależy ci, żeby zmienna była właśnie takiego typu i żeby kompilator pilnował tego od pierwszej linijki.

Zmienna bez wartości i bez typu to pułapka

Nie zostawiaj niejasnego let cos;. Jego typ początkowy to any, choć analiza przepływu może później śledzić przypisania. Jawny typ albo wartość początkowa jasno pokazują zamiar.

PRZYKŁAD Z OMÓWIENIEM

Karta postaci w grze

Program przechowuje statystyki bohatera, symuluje otrzymanie obrażeń i wypisuje raport. Wszystkie typy poznane w tej lekcji pracują tu razem.

src/index.ts
// ── dane, które nigdy się nie zmieniają ──
const nazwaPostaci = "Cień z Lęborka";
const MAKS_ZYCIA = 100;
const OBRAZENIA_OD_PULAPKI = 35;

// ── dane, które zmieniają się w trakcie gry ──
let zycie = MAKS_ZYCIA;
let poziom = 1;
let zloto = 12.5;
let czyZatruty = false;

// ── bohater wpada w pułapkę ──
zycie = zycie - OBRAZENIA_OD_PULAPKI;
czyZatruty = true;
zloto = zloto - 2.5;

// ── obliczenia pomocnicze ──
const procentZycia = (zycie / MAKS_ZYCIA) * 100;
const zyje = zycie > 0;

// ── raport ──
console.log("=== " + nazwaPostaci + " ===");
console.log("Poziom:    " + poziom);
console.log("Życie:     " + zycie + "/" + MAKS_ZYCIA + "  (" + procentZycia + "%)");
console.log("Złoto:     " + zloto.toFixed(2) + " szt.");
console.log("Zatruty:   " + (czyZatruty ? "tak" : "nie"));
console.log("Stan:      " + (zyje ? "walczy dalej" : "koniec gry"));
wynik w konsoli
=== Cień z Lęborka ===
Poziom:    1
Życie:     65/100  (65%)
Złoto:     10.00 szt.
Zatruty:   tak
Stan:      walczy dalej

Omówienie

LiniaDlaczego tak
const MAKS_ZYCIA = 100; Wartość ustalona raz na zawsze, więc const. Wersaliki sygnalizują, że to stała konfiguracyjna. Typ number został wywnioskowany.
let zycie = MAKS_ZYCIA; Zaczyna od pełnej puli, ale będzie się zmieniać — dlatego let. Typ też wywnioskowany, bo MAKS_ZYCIA jest liczbą.
zycie = zycie - OBRAZENIA_OD_PULAPKI; Prawa strona liczy się pierwsza (100 − 35), dopiero wynik trafia do zmiennej. Zapis skrócony to zycie -= 35;
const zyje = zycie > 0; Porównanie daje wartość logiczną, więc zyje ma typ boolean bez żadnego if.
zloto.toFixed(2) Zamienia liczbę na tekst z dwoma miejscami po przecinku. Zwraca string — dlatego wynik to "10.00", a nie 10.
czyZatruty ? "tak" : "nie" Operator warunkowy: jeśli warunek jest prawdziwy, weź wartość przed dwukropkiem, w przeciwnym razie tę po nim.

Sprawdź to sam

Zmień OBRAZENIA_OD_PULAPKI na 120 i uruchom program ponownie. Zobaczysz ujemne życie i „koniec gry”. Potem spróbuj przypisać coś do MAKS_ZYCIA — kompilator natychmiast zaprotestuje.

PRAKTYKA

Zamiana typów

Wartość może trafić do programu jako tekst, np. „42”. Zanim policzysz na takim tekście, przekształć go świadomie. Dane z innych źródeł nie zawsze są tekstem — po odczytaniu JSON mogą być także liczbą, obiektem lub tablicą.

src/index.ts
const wpisane = "42";

// tekst → liczba
const jakoLiczba = Number(wpisane);          // 42
const calkowita = parseInt("3.99", 10);      // 3   (obcina część dziesiętną)
const rzeczywista = parseFloat("3.99");      // 3.99

// liczba → tekst
const liczba = 255;
const tekst = String(liczba);                // "255"
const zDwoma = liczba.toFixed(2);            // "255.00"
const dwojkowo = liczba.toString(2);         // "11111111"

// cokolwiek → boolean
const czyPuste = Boolean("");                // false
const czyCos = Boolean("abc");               // true

console.log(jakoLiczba + 8);                 // 50  — dodawanie liczb
console.log(wpisane + 8);                    // 428 — sklejanie tekstu!

Gdy zamiana się nie uda

Number("abc") nie zgłasza błędu — zwraca specjalną wartość NaN (not a number). Co gorsza, NaN ma typ number, więc kompilator niczego nie zauważy. Trzeba to sprawdzić samodzielnie:

src/index.ts
const podane = "trzydzieści";
const wynik = Number(podane);

console.log(wynik);                  // NaN
console.log(wynik + 10);             // NaN — zaraża wszystkie obliczenia
console.log(Number.isNaN(wynik));    // true — tak to wykrywasz

if (Number.isNaN(wynik)) {
  console.log("To nie jest poprawna liczba!");
}

Nigdy nie porównuj z NaN przez ===

wynik === NaN zawsze daje false — nawet gdy wynik naprawdę jest NaN. To jedyna wartość w języku, która nie równa się samej sobie. Używaj wyłącznie Number.isNaN(…).

CZĘSTE BŁĘDY

Pięć pułapek początkującego

KodCo jest nie tak
const licznik = 0; licznik = 1; Wartości const nie da się podmienić. Tu powinno być let.
let suma; suma = suma + 5; Zmienna bez wartości początkowej ma undefined; wynik to NaN. Zawsze zaczynaj od let suma = 0;
const wiek: number = "18"; Cudzysłowy robią z tego tekst. Błąd TS2322.
console.log("5" + 3); Sklejanie zamiast dodawania — wynik "53". Najpierw Number("5").
const suma = 0.1 + 0.2; 0.1 + 0.2 daje 0.30000000000000004, ponieważ number używa binarnego zapisu zmiennoprzecinkowego. toFixed(2) formatuje wynik jako tekst; nie jest ogólnym sposobem porównywania liczb. Do przybliżonych pomiarów dobierz tolerancję, a proste kwoty licz w całych groszach.

Skąd tu if

W przykładach pojawia się instrukcja warunkowa if. Na razie wystarczy odczytać ją tak, jak brzmi: „jeżeli warunek jest prawdziwy, wykonaj to, co w klamrach”. Pełne omówienie — razem z else, zagnieżdżeniami i typowymi pułapkami — czeka w lekcji poświęconej if,else.

ZADANIA

Zadania

ZAD 1Rozgrzewka★☆☆

Bez uruchamiania programu zapisz, co wypisze każda linia. Potem sprawdź w edytorze.

zagadka.js — JavaScript; TS odrzuci działania tekst – liczba i boolean + liczba
console.log(10 + 5);
console.log("10" + 5);
console.log("10" - 5);
console.log(Number("10") + 5);
console.log(7 / 2);
console.log(true + 1);
pokaż rozwiązanie
15      dodawanie dwóch liczb
105     "+" przy tekście skleja
5       "-" nie ma wersji tekstowej, więc JS zamienia "10" na liczbę
15      jawna zamiana — tak trzeba to robić
3.5     jeden typ number, brak dzielenia całkowitego
2       true zamienia się w 1 (nie pisz tak w prawdziwym kodzie!)
ZAD 2Paragon ze sklepiku★☆☆

Zadeklaruj zmienne opisujące zakup: nazwę produktu, cenę jednostkową, liczbę sztuk oraz to, czy klient ma legitymację (rabat 10%). Policz i wypisz wartość przed rabatem, kwotę rabatu i kwotę do zapłaty — wszystkie z dokładnością do dwóch miejsc po przecinku. Zastanów się przy każdej zmiennej, czy powinna być let, czy const.

pokaż przykładowe rozwiązanie
const produkt = "kanapka";
const cena = 6.5;
const sztuk = 3;
const maLegitymacje = true;
const STAWKA_RABATU = 0.10;

const wartosc = cena * sztuk;
const rabat = maLegitymacje ? wartosc * STAWKA_RABATU : 0;
const doZaplaty = wartosc - rabat;

console.log("Produkt:    " + produkt + " x" + sztuk);
console.log("Wartość:    " + wartosc.toFixed(2) + " zł");
console.log("Rabat:      " + rabat.toFixed(2) + " zł");
console.log("Do zapłaty: " + doZaplaty.toFixed(2) + " zł");

Wszystko może być const, bo żadna wartość nie jest tu podmieniana — każda powstaje raz, na podstawie poprzednich.

ZAD 3Napraw kod★★☆

Ten program ma cztery błędy. Znajdź je, popraw i zapisz, jaki kod błędu zgłosił kompilator przy każdym z nich.

Celowy błąd TypeScript — znajdź i popraw przed uruchomieniem
const 1uczen: string = "Ala";
let srednia: number = "4.5";
const MAKS = 100;
MAKS = 120;
let wynik;
wynik = srednia * 2;
console.log(wynik.toUpperCase());
pokaż rozwiązanie
const uczen: string = "Ala";     // nazwa nie może zaczynać się od cyfry
let srednia: number = 4.5;       // TS2322 — liczba bez cudzysłowów
const MAKS = 100;                // TS2588 — usuwamy próbę podmiany
let wynik: number = 0;           // typ + wartość początkowa
wynik = srednia * 2;
console.log(wynik.toFixed(1));   // TS2339 — liczba nie ma toUpperCase()
ZAD 4Kalkulator BMI z walidacją★★☆

Masę i wzrost zapisz jako tekst, np. „72” i „1.78”. To ćwiczenie obliczania wzoru, nie ocena zdrowia. Odrzuć pusty tekst, nieskończoności i wartości niedodatnie. Dopiero potem policz masa / (wzrost * wzrost) i wypisz jedno miejsce po przecinku.

pokaż wskazówki

Po zamianie sprawdź Number.isFinite(masa) && Number.isFinite(wzrost) && masa > 0 && wzrost > 0. Przed konwersją sprawdź też, czy teksty po trim nie są puste. Samo !Number.isNaN nie odrzuca Infinity ani zera.

ZAD 5Konwerter systemów★★★

Zapisz w zmiennej liczbę całkowitą (np. 202) i wypisz ją w czterech postaciach: dziesiętnej, dwójkowej, ósemkowej i szesnastkowej. Skorzystaj z toString(podstawa). Następnie w drugą stronę: zamień tekst "1101" traktowany jako liczba dwójkowa na wartość dziesiętną — przyda się drugi argument parseInt.

pokaż rozwiązanie
const liczba = 202;

console.log("DEC: " + liczba.toString(10));   // 202
console.log("BIN: " + liczba.toString(2));    // 11001010
console.log("OCT: " + liczba.toString(8));    // 312
console.log("HEX: " + liczba.toString(16));   // ca

const binarnie = "1101";
const dziesietnie = parseInt(binarnie, 2);
console.log(binarnie + " (2) = " + dziesietnie + " (10)");   // 13

Podawaj podstawę jawnie, aby zamiar był czytelny. Współczesne parseInt(„010”) daje 10, a prefiks 0x może oznaczać zapis szesnastkowy. parseInt odczytuje początkowy fragment, więc parseInt(„12abc”, 10) daje 12 — to nie walidacja całego tekstu.

Jeszcze dwa typy do rozpoznania

bigint, np. 123n, opisuje liczby całkowite poza ograniczeniem dokładności number; nie mieszaj go bezpośrednio z number w arytmetyce. symbol pozwala tworzyć unikalne klucze. Nie potrzebujemy ich w pierwszych zadaniach, ale nie są odmianami string ani number.

PODSUMOWANIE

Co trzeba zapamiętać

  • const domyślnie, let tylko gdy wartość musi się zmieniać, var nigdy.
  • Typ podaje się po dwukropku, ale przy podanej wartości początkowej zwykle nie trzeba go pisać.
  • Typ ustala się w momencie deklaracji i później się nie zmienia — nawet gdy go nie zapisałeś.
  • Jeden typ number obsługuje liczby całkowite i dziesiętne; 7 / 2 to 3.5.
  • Number(…), parseInt(…, 10), String(…), toFixed(n) — podstawowe zamiany typów.
  • Nieudana zamiana daje NaN; wykrywasz ją wyłącznie przez Number.isNaN(…).