Paulund

TypeScript Type vs Interface: When to Use Each

In this article we're going to investigate what is the difference between TypeScript type and interface and when to use each one.

TypeScript Type

The Typescript type keyword is used to define a new type. It can be used to define a type for a primitive, union, tuple, or any other custom type like these:

  • String
  • Boolean
  • Number
  • Array
  • Tuple
  • Enum
  • Advanced types
type Person = {
  name: string;
  age: number;
};

const person: Person = {
  name: 'John',
  age: 30,
};

TypeScript Interface

The TypeScript interface keyword is used to define a new type. It can be used to define a type for an object, class, or function.

interface Person {
  name: string;
  age: number;
}

const person: Person = {
  name: 'John',
  age: 30,
};

When to Use Them

As you can see from the above examples is that type and interface can be used interchangeably in most cases. However, there are some differences between them.

Use type when you need to define a union, tuple, or any other custom type.

type Status = 'active' | 'inactive';

type Point = [number, number];

Type Intersection

TypeScript allows you to combine multiple types into one using the & operator. This is called type intersection.

type Person = {
  name: string;
};

type Employee = {
  job: string;
};

type EmployeePerson = Person & Employee;

const employeePerson: EmployeePerson = {
  name: 'John',
  job: 'Developer',
};

Type Omits

TypeScript allows you to omit properties from a type using the Omit utility type.

type Person = {
  name: string;
  age: number;
  job: string;
};

type PersonWithoutJob = Omit<Person, 'job'>;

const personWithoutJob: PersonWithoutJob = {
  name: 'John',
  age: 30,
};

Type Pick

TypeScript allows you to pick properties from a type using the Pick utility type.

type Person = {
  name: string;
  age: number;
  job: string;
};

type PersonName = Pick<Person, 'name'>;

const personName: PersonName = {
  name: 'John',
};

Type Readonly

TypeScript allows you to make all properties of a type readonly using the Readonly utility type.

type Person = {
  name: string;
  age: number;
};

type ReadonlyPerson = Readonly<Person>;

const person: ReadonlyPerson = {
  name: 'John',
  age: 30,
};

// Error: Cannot assign to 'name' because it is a read-only property.
person.name = 'Jane';

Type Partial

TypeScript allows you to make all properties of a type optional using the Partial utility type.

type Person = {
  name: string;
  age: number;
};

type PartialPerson = Partial<Person>;

const person: PartialPerson = {
  name: 'John',
};

// Error: Property 'age' is missing in type '{ name: string; }' but required in type 'Person'.

Type Required

TypeScript allows you to make all properties of a type required using the Required utility type.

type Person = {
  name?: string;
  age?: number;
};

type RequiredPerson = Required<Person>;

const person: RequiredPerson = {
  name: 'John',
  age: 30,
};

// Error: Property 'age' is missing in type '{ name: string; }' but required in type 'Person'.

Type Record

TypeScript allows you to create a type with a given set of keys and values using the Record utility type.

type Person = {
  name: string;
  age: number;
};

type PersonRecord = Record<string, Person>;

const personRecord: PersonRecord = {
  john: {
    name: 'John',
    age: 30,
  },
  jane: {
    name: 'Jane',
    age: 25,
  },
};

Type Exclude

TypeScript allows you to exclude properties from a type using the Exclude utility type.

type Person = {
  name: string;
  age: number;
  job: string;
};

type PersonWithoutJob = Exclude<keyof Person, 'job'>;

const personWithoutJob: PersonWithoutJob = 'name' | 'age';

Type Extract

TypeScript allows you to extract properties from a type using the Extract utility type.

type Person = {
  name: string;
  age: number;
  job: string;
};

type PersonJob = Extract<keyof Person, 'job'>;

const personJob: PersonJob = 'job';

Type NonNullable

TypeScript allows you to create a type that excludes null and undefined from a given type using the NonNullable utility type.

type Person = {
  name: string;
  age: number | null;
};

type NonNullablePerson = NonNullable<Person>;

const person: NonNullablePerson = {
  name: 'John',
  age: 30,
};

// Error: Property 'age' is missing in type '{ name: string; }' but required in type 'Person'.

Interface Extending

Whereas you should use interface when you are defining an object, class, or function. Which means an interface can be used on an object for extending another class.

interface Animal {
    name: string;
}

interface Dog extends Animal {
    breed: string;
}

class MyDog implements Dog {
    name = 'Rex';
    breed = 'Labrador';
}

Interface declarations with the same name can be merged, while type declarations with the same name will throw an error.

interface Person {
  name: string;
}

interface Person {
  age: number;
}

const person: Person = {
  name: 'John',
  age: 30,
};

Conclusion

In conclusion, use type when you need to define a union, tuple, or any other custom type. Use interface when you are defining an object, class, or function.

The default choice you can commonly go for is to use type in the majority of cases, this is because you have more options as to what can be defined as an type.