Use which: Interface or Type Alias in Typescript?
Published: 2023-01-04 05:01:21

This blog mainly discusses the key differences of `interface vs type`, and share how I would use them in my daily software development routine.
                                                                    

### Describe the shape of an object or a function signature

Both can be used to describe the shape of an object or a function signature. 

However, I mostly use `interface` to describe the object, and use `type` to describe a function signature, as  I can clearly know it’s a definition for function from `arrow function`, which is impossible to realize in `interface`.

```typescript
interface Point {
  x: number;
  y: number;
}

type SetPoint = (x: number, y: number) => void;
```
Another scenario where I use interface is for 「Index Signatures」. For example, in dynamic generated input,  we don’t know all the names of a type’s properties ahead of time, but we do know the shape of the values.  

```typescript
interface Input {
  [index: string]: string | number;
}
```

### Extending and Intersection Types

At first sight, extending and intersection are similar ways to combine types. However, the principle difference between the two is **how conflicts are handled**.

For `interface`, If you declare a property with the same key, it will overrides the one in the derived interface. However, it should be compatible with the previous one, or typescript compiler will throw an error.

```typescript
// This works pretty well, as it is compatible
interface Converter {
  convert: (value: number) => string;
}

interface StringNumberConverter extends Converter {
  convert: (value: number | string) => string;
}

// Oops...this will throw an error, as it is incompatible
interface Converter {
  convert: (value: number) => string;
}

interface StringNumberConverter extends Converter {
  convert: (value: string) => string;
}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/856p7ujgy7jrycm9o9rw.png)
For type, properties with the same key don’t have to be compatible. You can declare whatever you like. 

```typescript
type Converter = {
  convert: (value: number) => string;
}

type StringNumberConverter = Converter & {
  convert: (value: string) => string;
}
```
Another difference you should pay attention is the meaning they represent. When I use interface, I want it stands for the「Parent-Child」relationship. By contrast, when I use type, it only stands for 「Composition」relationship. 

```typescript
// 「Parent-Child」relationship. Cat derives from Animal.
interface Animal {
  name: string;
}

interface Cat extends Animal {
  color: string;
}

// 「Composition」relationship. Color and Size are two seperate species
type Color = {
  name: string
}
type Size = {
  size: 'small' | 'medium' | 'large'
}

type ColorSize = Color & Size
```

### Class Implements

A class can implement an interface or type alias, but it can not implement Union type, as in typescript, a class can only implement an object type or intersection of object types with **statically known members**. 

So in daily development, if this type is designed to be implemented by class, I will use `interface` over `type`.

```typescript
type PartialPoint = { x: number; } | { y: number; };

// can not implement a union type
class SomePartialPoint implements PartialPoint {
  x = 1;
  y = 2;
}
```
### More than Object Types

Unlike an interface, type alias can also be used for other types. Frequently used are such as  union type and tuples.

```typescript
type StringNumberPair = [string, number];
function doSomething(stringHash: [string, number]) {
  const [inputString, hash] = stringHash;
  console.log(inputString); // string
  console.log(hash);  // number        
}
```

### Declaration Merging

`interface` is open, and `type alias` is close within itself. An interface can be defined multiple times, and will be treated as a single interface with members of all declarations being merged.

```typescript
type Bear = {
  name: string;
}
// Error：Duplicate Identifier
type Bear = {
  age: number;
}

// works pretty well
interface Bear {
  name: string;
}

interface Bear {
  age: number;
}

const b: Bear = {
  name: '',
  age: 0
}
```
### Working With `typeof`  Type Operator

In most cases, if you want to work with `typeof` type operator, choose `type` over `interface`.
```typescript
function f() {
  return { x: 10, y: 3 };
}

type P = ReturnType<typeof f>;

/**
** type P = {
    x: number;
    y: number;
}
**/
```

### Conclusion

When the next time you are confused which to use, try this cheatsheet!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/58gx45rg9kwbv1muil6v.png)