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 upotrebe | Preporuka |
|---|---|
| Modeli podataka (User, Product, Order) | interface |
| Props komponenti | interface |
| Store state (Redux, Zustand, Valtio) | interface |
| Tipovi API odgovora | type |
| Vrijednosti formi | type |
| Union tipovi | type |
| Function tipovi | type |
| Intersection tipovi | type |
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.







