Kada koristiti Type, a kada Interface

Kada koristiti Type, a kada InterfaceKada koristiti Type, a kada Interface

28. stu. 2025. - 12 min

Roko Ponjarac

Roko Ponjarac

Software Engineer


Type i interface su dva glavna alata u TypeScriptu za definiranje oblika objekata. Oba rade slične stvari, ali svaki ima svoje prednosti. Ovaj vodič objašnjava kada koristiti jedan, a kada drugi, uz praktične primjere koda koje možete koristiti u stvarnim projektima.

Osnove

Prvo ćemo razjasniti što svaki konstrukt radi i kako se razlikuju na osnovnoj razini prije nego što ih počnemo uspoređivati.

Što je Type Alias?

Type alias daje ime bilo kojem tipu. Možete definirati pravila za primitive, unije, tuple, objekte i složenije kombinacije. Ključna riječ type omogućuje stvari koje interfejsi ne mogu.

// Union type — nije moguće s interfejsom
type Status = 'pending' | 'approved' | 'rejected';

// Tuple type
type Coordinates = [number, number];

// Function type
type Validator = (value: string) => boolean;

Type aliasi su izvrsni za prikaz oblika podataka koji nisu objekti. Kada vaša aplikacija treba union tipove za upravljanje stanjem ili API odgovorima, tipovi su vrlo važni.

Što je Interface?

Interface postavlja pravila za strukturu objekta. Interfejsi dolaze iz klasičnog objektno-orijentiranog programiranja i još uvijek se koriste u TypeScriptu.

interface User {
  id: string;
  name: string;
  email: string;
}

interface Product {
  id: string;
  name: string;
  description?: string;
  price: number;
}

Interfejsi se bave samo oblicima objekata. Developerima koji poznaju Javu, C# ili druge OOP jezike njihova sintaksa će biti poznata.

Glavne razlike između Type i Interface

Poznavanje tehničkih razlika pomaže vam donositi pametne odluke u kodu.

Declaration Merging

Interfejsi omogućuju spajanje deklaracija. TypeScript uzima više deklaracija interfejsa s istim imenom i kombinira ih u jednu definiciju. Tipovi to ne dopuštaju.

// Spajanje deklaracija interfejsa
interface Window {
  customProperty: string;
}

interface Window {
  anotherProperty: number;
}
// Window sada ima oba svojstva

// Type se ne može ponovno deklarirati — Greška!
type Response = { data: string };
type Response = { error: string }; // Error: Duplicate identifier

Kada želite proširiti tipove u biblioteci treće strane, spajanje deklaracija može biti korisno. Ovaj uzorak vam omogućuje proširenje vlastite teme kada radite s Material UI temom.

Proširivanje i presjeci

Oba konstrukta omogućuju proširivanje, ali sintaksa je različita. Interfejsi koriste ključnu riječ extends. Tipovi koriste operatore presjeka.

// Proširenje interfejsa
interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

// Presjek tipova
type Animal = { name: string };
type Dog = Animal & { breed: string };

Union tipovi

Tipovi upravljaju unijama. Interfejsi ne mogu izravno stvarati unije.

type Result<T> = { success: true; data: T } | { success: false; error: string };

type LoadingState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: Error };

Ovaj uzorak se često koristi u React aplikacijama za state machine i API odgovore.

Mapped i Computed tipovi

Tipovi mogu imati izračunata svojstva i mapped tipove koji vam omogućuju stvaranje novih tipova u hodu.

type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

type EventName = `on${Capitalize<'click' | 'focus' | 'blur'>}`;
// Output: "onClick" | "onFocus" | "onBlur"

Pravila za projekte u produkciji

Konzistentna pravila su dobra za produkcijske kodne baze. Evo metode koja je isprobana i provjerena u enterprise React aplikacijama.

Matrica odabira

Tablica ispod pokazuje kada koristiti svaki konstrukt:

Slučaj upotrebePreporuka
Modeli podataka (User, Product, Order)interface
Props komponentiinterface
Store state (Redux, Zustand, Valtio)interface
Tipovi API odgovoratype
Vrijednosti formitype
Union tipovitype
Function tipovitype
Intersection tipovitype

Ova matrica se temelji na jednom pravilu: koristite interface za strukture koje pokazuju "kako nešto izgleda" i type za "što se šalje ili prima."

Modeli podataka s Interface

Modeli podataka pokazuju kako su stvari u vašoj aplikaciji povezane. Interfejsi su dobri za ovo jer opisuju strukture objekata i omogućuju proširivanje.

export interface UserModel {
  id: number;
  fullName: string;
  email: string;
  roles: UserRole[];
  userStatus: UserStatus;
}

export interface RecordsModel {
  id: number;
  userId: number;
  clockInDate: string;
  clockOutDate: string;
}

Kada modeli imaju ista polja, proširivanje interfejsa održava kod DRY:

export interface BaseEntity {
  id: number;
  createdAt: string;
  updatedAt: string;
}

export interface RecordsModel extends BaseEntity {
  userId: number;
  clockInDate: string;
}

Tipovi API odgovora s Type

API granice se bave transformacijom podataka. Tipovi se brinu o složenim uzorcima koje ove situacije zahtijevaju.

export type PayloadResponse<T> = {
  payload: T;
  message?: string;
};

export type PaginatedResponse<T> = {
  entities: T[];
  totalCount: number;
  pagination?: {
    pageNumber: number;
    pageSize: number;
  };
};

Vrijednosti formi s Type

Prije validacije, vrijednosti formi pokazuju što je korisnik upisao. Tipovi dobro funkcioniraju jer forme često trebaju union tipove za select polja.

export type LoginFormValues = {
  email: string;
  password: string;
};

export type CreateUserFormValues = {
  fullName: string;
  email?: string;
  department: 'sales' | 'engineering' | 'marketing';
};

Store State s Interface

Store-ovi za upravljanje stanjem određuju strukturu stanja aplikacije. Interfejsi to jasno prikazuju.

interface AuthStore {
  user: UserModel | null;
  authenticating: boolean;
  token: string | null;
}

interface UsersStore {
  users: UserModel[];
  selectedUser?: UserModel;
  isLoading: boolean;
  totalCount: number;
}

Primjeri iz prakse s React i Next.js

U frontend developmentu postoje određene situacije gdje je važno koristite li type ili interface.

Props komponenti

Oba rade za definiranje React props-a. Uzorak u zajednici preferira korištenje interfejsa za props.

interface ButtonProps {
  variant: 'primary' | 'secondary' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  onClick: () => void;
  children: React.ReactNode;
}

function Button({ variant, size = 'md', onClick, children }: ButtonProps) {
  return (
    <button className={`btn btn-${variant} btn-${size}`} onClick={onClick}>
      {children}
    </button>
  );
}

Intersection tipovi su odlični za proširivanje HTML element props-a:

type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
  label: string;
  error?: string;
};

Function i Callback tipovi

Potpisi funkcija trebaju imati vlastite tipove. Ovaj uzorak poboljšava čitljivost.

export type FormSubmitHandler<T> = (data: T, methods: UseFormReturn<T>) => void | Promise<void>;

type ValidationFn<T = string> = (value?: T) => true | string;

Globalni Type uzorci

Internacionalizacija

Tipizirani ključevi prijevoda sprječavaju runtime greške kada radite React aplikacije koje podržavaju više jezika.

type TranslationNamespace = 'common' | 'auth' | 'dashboard' | 'errors';

interface LocaleConfig {
  code: string;
  name: string;
  direction: 'ltr' | 'rtl';
}

Ova metoda dobro funkcionira u Next.js postavkama prijevoda koje osiguravaju da ne propustite ključeve prijevoda održavanjem type safety-ja.

Markdown i statički sadržaj

Generatori statičkih stranica i blog sustavi trebaju moći upravljati tipiziranim sadržajem. Evo kako tipovi i interfejsi surađuju za statičke stranice napravljene s Markdownom.

// Union type — koristi type
export type BlogCategory = 'development' | 'design' | 'marketing';

// Struktura podataka — koristi interface
export interface BlogPost {
  slug: string;
  title: string;
  date: string;
  category: BlogCategory;
  featured: boolean;
}

// Proširena struktura — koristi interface
export interface BlogPostWithContent extends BlogPost {
  content: string;
}

Primijetite uzorak: BlogCategory koristi type jer je unija. BlogPost koristi interface jer predstavlja strukturu podataka.

Best practice i napredni uzorci

Uvjetni tipovi

Tipovi omogućuju uvjetnu logiku koju interfejsi ne mogu prikazati.

type ExtractArrayType<T> = T extends Array<infer U> ? U : never;

type StringArray = string[];
type ExtractedString = ExtractArrayType<StringArray>; // string

Generička ograničenja

Oba podržavaju generike, ali tipovi omogućuju fleksibilnija ograničenja.

type KeysOfType<T, V> = {
  [K in keyof T]: T[K] extends V ? K : never;
}[keyof T];

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

type StringKeys = KeysOfType<User, string>; // "name" | "email"

Uzorci Utility tipova

Napravite utility tipove koji se mogu koristiti više puta za uobičajene transformacije.

type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

// Upotreba: Učini "id" opcionalan za kreiranje
type CreateUserDTO = PartialBy<User, 'id'>;

Stvari koje ne biste trebali raditi

Miješanje stilova bez razloga

Odaberite konvenciju i držite je se. Nekonzistentna upotreba zbunjuje članove tima.

// Loše: Miješani pristup bez razloga
type UserProps = { name: string };
interface ProductProps { name: string }

// Dobro: Konzistentan pristup
interface UserProps { name: string }
interface ProductProps { name: string }

Prekomjerno korištenje Type

Tipovi nude više opcija, ali interfejsi su bolji za strukture objekata jer jasnije pokazuju vaše namjere.

// Nije najbolje: Type za jednostavan objekt
type User = { id: string; name: string };

// Bolje: Interface signalizira da je ovo struktura podataka
interface User {
  id: string;
  name: string;
}

Nekorištenje Declaration Merginga

Koristite interfejse da iskoristite declaration merging kada dodajete nove tipove u kod treće strane.

// Proširivanje Express Requesta
declare global {
  namespace Express {
    interface Request {
      user?: UserModel;
    }
  }
}

Razmatranja performansi

Performanse kompilacije TypeScripta malo variraju između tipova i interfejsa. Interfejsi stvaraju jedan ravni object type. Više kalkulacija je potrebno za pronalaženje presjeka složenih tipova.

Za većinu upotreba, ova razlika nije bitna. Stavite veći naglasak na jasnoću koda nego na mala poboljšanja.

Struktura direktorija za tipove

Organizirajte tipove prema njihovoj funkciji:

src/
├── types/                    # Koristi type — API tipovi i tipovi odgovora
│   ├── response.type.ts
│   └── blog.type.ts
├── models/                   # Koristi interface — modeli podataka
│   ├── user.model.ts
│   └── record.model.ts
├── components/               # Koristi interface — props komponenti
└── stores/                   # Koristi interface — store state

Ova struktura pokazuje što želite postići. Developeri znaju što očekivati u svakom folderu.

Razlog za odabir

Razlika je u riječima. Koristite type za tipove koji govore "što se šalje ili prima" (API, forme, callbackovi). Koristite interface za stvari koje govore "kako nešto izgleda", poput modela, props-a i store stanja.

Ovaj način razmišljanja je u skladu s razvojem TypeScripta. OOP konvencije dovele su do stvaranja interfejsa za postavljanje ugovora objekata. Tipovi su napravljeni za upravljanje promjenjivim uzorcima u JavaScriptu, poput unija i mapped tipova.

Spremni za razgovor?

Pošaljite kratki uvod kako bismo dogovorili uvodni poziv. Poziv se fokusira na vaše izazove i ciljeve te ocrtava prve korake prema pravom digitalnom rješenju.

Kada koristiti Type, a kada Interface | Workspace