Difference between typescript interface and type

Serhii Kholmohorov
4 min readJul 17, 2023

--

Stop using interfaces and types incorrectly. Interface vs type.

  • What to use for React component props?
  • What touse for DTO or entity structures?
  • Why does react-select use types to describe props, but react-router uses interfaces?
  • What is preferred to use — interface or type?

Present one difference between type alias and interface — interface declaration merging. And it does not affect on choice.

interface InputProps { // correct
value: string;
}
// and same
type InputProps = { // correct too
value: string;
}

All usages are correct. But I have 3 different variants of usage.

1. Officially its preferred to use interfaces over types.

Official docs tell:

If you would like a heuristic, use interface until you need to use features from type

2. Prefer using types. Types lover.

Interfaces are considered undesirable and are associated with the Java language. You use interfaces for declaration merging only.

3. Java, kotlin (and backend) lover. Clean archicture lover. Abstractions lover. Clean code lover.

If you come from the backend, you know that an interface is a structure that must be implemented.

// for save in DB
interface ActiveRecord {
save(): void;
}

// for auth
interface UserIdentity {
createSession(): boolean;
}

// combined entity
class User implements ActiveRecord, UserIdentity {
...
}

interface Application {
createUser(): User;
}

interface AuthService {
login(user: UserIdentity): boolean;
}

interface UserService {
setDetails(activeRecord: ActiveRecord, form: RegisterForm): void;
}

class ApiController extends RestController {
application: Application;
userService: UserService;
authService: AuthService;

// see below
register(form: RegisterForm) {
// create empty user
const user: User = this.application.createUser();
// UserService knows about CRUD DB operations and receive ActiveRecord objects
this.userService.setDetails(user, form);
// AuthService knows how create and validate sessions
this.authService.login(user);
}
{

Interface is communication

All communications between application layers (service, repository, controller), between parts of system (form and controller, or view model, or presenter), and between systems (API) — are interfaces.

interface BankAPI {
pay(Payment): Promise<Transaction>;
}

const monoBank: BankAPI = application.getBank();
const payment: Payment = {
"amount": 1000,
"currencyId": 840 // USD
}
const transaction: Transaction = await monoBank.pay(payment);
// do something with transaction

We know nothing about the implementation. We only know how to create data for payment and what answers we can receive.

Mobile or web applications (UI) serve as the interface between the user and a complex system. Users don’t need to know anything about microservices or databases. An interface is a simplification of something complicated. For example, a car’s transmission and steering wheel serve as interfaces for car control.

No need to implement an interface for object creation; you can cast to the interface.

interface Account {
name: string;
}

// implementation is not required
class AccountImpl implements Account {
name: string;
constructor(name: string) {
this.name = name;
}
}

// returns object with Account interface
function createAccount(name: string): Account {
return {
name
}
}

But when do you use types in structures?

When you don’t need to know the full object (shape) structure, but only a partial one


type WithId = { // its a part of smthg structure which minimum has ID field
id: string;
}

interface List<T> {
elements: T[];
get(id: string): T | undefined;
}

abstract class ListAbstract<T extends WithId> implements List<T> {
elements: T[];
get(id: string): T | undefined {
return this.elements.find(element => element.id === id);
}
}

// extending of WithId is not requierd, you should have id field only
interface Animal {
id: string;
type: string;
}

interface Account{
id: string;
getBalance(): number;
}

// dont throw errors
class AnimalList extends ListAbstract<Animal> {}
class AccountList extends ListAbstract<Account> {}

or interface solution

// backend way like with extending
interface WithId {
id: string;
}
// extends from needle interface
interface Animal extends WithId {
type: string;
}

interface Account extends WithId {
getBalance(): number;
}

class AnimalList extends ListAbstract<Animal> {}
class AccountList extends ListAbstract<Account> {}

Type is about combinations or variants of primitives, not structure.

Type is about combining data types — union, exclusion, picking, and others.

type inputType = 'text' | 'password';
type Nullable<T> = T | null;
type callback = (name: string) => Promise<number>;
type User = Pick<Transaction, "status">; // its keep part of data structure

Conclusion

Use INTERFACE for:

- describing data structure (DTO, parameters, forms, React props, classes)
- describing behavior (public methods, view models, API)

Use TYPE for:

- defining primitive types
- defining complex types — conditional, union, exclusion, picking and other combination of data types

Thank you for reading. Think in terms of interfaces!

--

--

Serhii Kholmohorov
Serhii Kholmohorov

Responses (1)