TypeScript odavno nije samo "JavaScript s tipovima" — sustav tipova je dovoljno moćan da riješi probleme koje bi inače morali loviti u produkciji. Problem je što većina developera koristi tek mali dio tih mogućnosti. Evo nekoliko trikova koje rijetko vidite u svakodnevnom kodu, a mogu značajno podići kvalitetu i sigurnost projekta.

1. satisfies umjesto direktne anotacije tipa

Klasična anotacija tipa (: Type) proširuje tip promjenjive na deklarirani tip — što znači da gubite preciznije, uže tipove koje bi TypeScript inače zaključio. satisfies provjerava da vrijednost odgovara tipu, ali zadržava izvedeni (inferirani) tip.

type Boja = "crvena" | "zelena" | "plava";

// bez satisfies - tip postaje Record<string, Boja>
const config: Record<string, Boja> = { primarna: "crvena", sekundarna: "plava" };

// sa satisfies - tip ostaje { primarna: "crvena", sekundarna: "plava" }
const config2 = { primarna: "crvena", sekundarna: "plava" } satisfies Record<string, Boja>;

config2.primarna; // tip je točno "crvena", ne generički Boja

2. as const za nepromjenjive nizove kao izvor tipova

Umjesto da ručno pišete union tip i zaseban niz vrijednosti (koji lako izađu iz sinkronizacije), izvedite tip izravno iz niza:

const STATUSI = ["na_cekanju", "u_obradi", "zavrseno"] as const;
type Status = (typeof STATUSI)[number]; // "na_cekanju" | "u_obradi" | "zavrseno"

Dodate li novi status u niz, tip se automatski ažurira — nema rizika da tip i stvarne vrijednosti postanu neusklađeni.

3. Template literal tipovi za precizne stringove

TypeScript može tipizirati oblik stringa, ne samo da je nešto string:

type RutaAPI = `/api/${string}`;
type CSSVarijabla = `--${string}`;
type EventIme = `on${Capitalize<string>}`;

function pozovi(ruta: RutaAPI) { ... }
pozovi("/api/korisnici");  // ✅
pozovi("korisnici");        // ❌ tip greška

Korisno za rutiranje, CSS varijable, i18n ključeve ili bilo koji konvenciju imenovanja koju želite provoditi na razini tipova.

4. Discriminated unions umjesto opcionalnih polja

Umjesto tipa gdje su polja opcionalna "ovisno o slučaju" (što dovodi do provjera poput if (x.tip === "a" && x.vrijednostA)), koristite zajedničko diskriminirajuće polje:

type Rezultat =
  | { status: "uspjeh"; podaci: string }
  | { status: "greska"; poruka: string };

function obradi(r: Rezultat) {
  if (r.status === "uspjeh") {
    console.log(r.podaci); // TypeScript zna da postoji "podaci"
  } else {
    console.log(r.poruka); // i da ovdje postoji "poruka"
  }
}

TypeScript automatski suzi (narrow) tip unutar svakog grananja — bez potrebe za ručnim provjerama !== undefined.

5. never za iscrpne (exhaustive) provjere u switch iskazima

Ako dodate novi slučaj u union tip, a zaboravite ga obraditi u switchu, ovaj trik hvata grešku u vrijeme kompajliranja, ne u produkciji:

function opisiStatus(status: Status): string {
  switch (status) {
    case "na_cekanju": return "Na čekanju";
    case "u_obradi": return "U obradi";
    case "zavrseno": return "Završeno";
    default:
      const _iscrpno: never = status;
      throw new Error(`Nepokriven status: ${_iscrpno}`);
  }
}

Dodate li novi status u STATUSI niz iz trika #2, a zaboravite dodati case ovdje, TypeScript prijavljuje grešku na liniji s never.

6. Utility tipovi koje malo tko koristi: Parameters i ReturnType

Umjesto da ručno duplicirate tip parametara ili povratne vrijednosti neke funkcije, izvucite ih izravno iz nje:

function stvoriKorisnika(ime: string, email: string, aktivan: boolean) { ... }

type ParametriStvaranja = Parameters<typeof stvoriKorisnika>;
// [ime: string, email: string, aktivan: boolean]

type PovratStvaranja = ReturnType<typeof stvoriKorisnika>;

Posebno korisno kod wrapper funkcija ili testova gdje ne želite duplicirati potpis funkcije.

7. readonly i Readonly<T> za sprječavanje slučajnih mutacija

function ispisiStavke(stavke: readonly string[]) {
  stavke.push("nova"); // ❌ tip greška - readonly niz
}

interface Konfiguracija {
  readonly apiKljuc: string;
}

Posebno korisno za props komponenti ili konfiguracijske objekte koji ne bi trebali biti mijenjani nakon inicijalizacije.

Zaključak

Ovi trikovi ne mijenjaju kako TypeScript radi u pozadini — samo bolje koriste ono što jezik već nudi. Najveći dobitak dolazi od satisfies, as const i discriminated unions, jer izravno sprječavaju cijele kategorije bugova (neusklađene konstante, nedostajuće provjere, pristup nepostojećim poljima) prije nego što kod uopće stigne do produkcije.