Wyrażenie switch, czyli alternatywa dla if + QUIZ

TIP: Cały kod do poszczególnych lekcji, dodatkową teorię i linki z tej i innych lekcji - znajdziesz w darmowym repozytorium - https://github.com/jaktestowac/typescript-dla-testera Chcesz dokładniej poznać TypeScript? Sprawdź nasz Program JavaScript i TypeScript dla Testerów

Prezentacja

Tu w przyszłości mogą pojawić się dodatkowe materiały w postaci prezentacji etc.

Dodatkowe materiały

Konstrukcja switch to czytelna alternatywa dla wielu if/else if przy podejmowaniu decyzji na podstawie konkretnych wartości (np. string, number, enum).

Sprawdza się, gdy masz kilka równorzędnych przypadków. Do zakresów/warunków złożonych zwykle lepszy będzie if.

Najważniejsze tematy w tej lekcji:

  • Składnia switch (expr) { case ...: ...; break; default: ... } i rola break.
  • Dobre praktyki: unikanie niechcianego fall-through, grupowanie przypadków, early return.
  • Proste użycie z typami dosłownymi i enumami; egzekwowanie kompletności przypadków.
  • Kiedy nie używać switch: warunki zakresowe, pojedynczy boolean, bardzo proste decyzje.

Podstawowe użycie switch z przerwaniem break:

// Basic switch with break
const env = (process.env.ENV ?? 'dev').toLowerCase();


let baseUrl: string;
switch (env) {
  case 'prod':
    baseUrl = 'https://api.myapp.com';
    break;
  case 'staging':
    baseUrl = 'https://staging.myapp.com';
    break;
  case 'dev':
  default:
    baseUrl = 'http://localhost:3000';
    break;
}
console.log(baseUrl);
  

Grupowanie przypadków i early return poprawiają czytelność.

// Group related cases; return early -> no need for break
function severityIcon(level: 'info' | 'warn' | 'error' | 'fatal'): string {
  switch (level) {
    case 'info':
      return 'ℹ️';
    case 'warn':
      return '⚠️';
    case 'error':
    case 'fatal': // grouped
      return '🔥';
    default: {
      // exhaustive check (will error if new value appears)
      const _never: never = level;
      return _never;
    }
  }
}
  

Unikaj niezamierzonego fall-through. Jeśli jest celowy — dodaj komentarz.

// ❌ Missing break -> unintended fall-through
switch (command) {
  case 'start':
    startJob();
    // break; // missing -> will also run 'status'
  case 'status':
    printStatus();
    break;
}


// ✅ Intentional fall-through is documented
switch (command) {
  case 'init':
    setup();
    // falls through
  case 'start':
    startJob();
    break;
  default:
    help();
    break;
}
  
Dobre praktyki:

  • Prosto: jeden, krótki efekt w każdym case (np. return lub przypisanie).
  • Break/return: kończ każdy przypadek. Unikaj cichego fall-through.
  • Default: dodaj sensowną gałąź default (log/throw/wartość domyślna).
  • Kompletność: dla unii/enumów rozważ wzorzec z never, by kompilator pilnował wszystkich przypadków.
  • Nie nadużywaj: dla pojedynczego warunku lub zakresów (>, <=) lepszy będzie if/else.
  • Wejście: ujednolić porównania (np. value.toLowerCase()), aby uniknąć duplikatów.

Linki zewnętrzne

Zadania

Przygotowaliśmy dla Ciebie kilka zadań-zagadek, które pozwolą Ci utrwalić wiedzę 😉

Zadanie 1

Treść zadania: Co zostanie wyświetlone w konsoli?

const status = 'warn';

switch (status) {
  case 'ok':
    console.log('OK');
    break;
  case 'warn':
    console.log('WARN');
  case 'error':
    console.log('ERROR');
    break;
  default:
    console.log('DEFAULT');
}
Rozwiązanie i analiza
Brak break po 'warn' powoduje tzw. fall-through — wykona się również kolejny przypadek.

Odpowiedź: wypisze kolejno: WARN i ERROR.

Zadanie 2

Treść zadania: Jaki będzie wynik w konsoli?

function canEdit(role: 'admin' | 'editor' | 'viewer'): boolean {
  switch (role) {
    case 'admin':
    case 'editor':
      return true;
    case 'viewer':
      return false;
  }
}

console.log(canEdit('viewer'));
Rozwiązanie i analiza
Przypadki są zgrupowane: 'admin' i 'editor' zwracają true, 'viewer' zwraca false.

Odpowiedź: false.

Zadanie 3

Treść zadania: Co trafi do konsoli i dlaczego?

const cmd = 'Start';

switch (cmd) {
  case 'start':
    console.log('A');
    break;
  case 'stop':
    console.log('B');
    break;
  default:
    console.log('C');
}
Rozwiązanie i analiza
Porównania w switch są ścisłe (jak ===) i wrażliwe na wielkość liter. 'Start' nie równa się 'start'.

Odpowiedź: C.

Zadanie 4

Treść zadania: Co zostanie wypisane?

let i = 0;

switch (++i) {  // expression evaluated once, then matched strictly
  case 1:
    console.log('one');
    break;
  case 2:
    console.log('two');
    break;
}
console.log(i);
Rozwiązanie i analiza
Najpierw ++i zwiększa i do 1, więc pasuje do case 1, a po break wychodzimy ze switch. Na końcu wypisujemy bieżącą wartość i.

Odpowiedź: najpierw one, potem 1.

6 komentarzy

    1. Hej,
      Taka deklaracja jest możliwa, ale w tej formie nie zalecana 😉

      Samo użycie union types jest dobre, bo:
      – ogranicza możliwe wartości (type safety)
      – daje lepsze podpowiedzi w IDE
      – zapobiega błędom.

      Natomiast to przypisanie:

      day = 1 as 1|2|3|4|5|6|7
      

      jest zbędne bo robisz cast, który nic nie wnosi (a omijasz system typów).

      Wystarczy:

      let day: 1 | 2 | 3 | 4 | 5 | 6 | 7 = 1
      

      Albo :
      [/js]
      type Day = 1 | 2 | 3 | 4 | 5 | 6 | 7
      let day: Day = 1
      [/js]

  1. W ćwiczeniu : 3-1-switch-statement.ts
    jest instrukcja:
    1. Create a function called `getDayName` that takes a number parameter (1-7)

    tymczasem funkcje poruszane są dopiero 2 moduły dalej 😉

    Chyba, że ktoś najpierw robi zadania pod filmem to znajdzie przykład (już w zadaniu 2)
    albo zamiast function powinno być variable?

    Avatar Jacek Kraś

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *