TypeScript: type vs interface
Tags: typescript, javascript, beginners, webdev
Published: 2023-01-23 00:56:20

Let's resolve this forever outstanding question:
Should I use `type` or `interface`?

**Spoiler:** *It's called "TypeScript" not "InterfaceScript"* 😉

## Why a resolution is needed?

Typescript [documentation](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces) is itself vague about which one should be used. However, vagueness is not helpful while creating a reliable software. 

> Most programming languages contain good parts and bad parts. I discovered that I could be a better programmer by using only the good parts and avoiding the bad parts. After all, how can you build something good out of bad parts?

*Douglas Crockford*

> In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.

*Zen of Python*

## type - Good, interface - Bad


### 1. `interface` is mutable
Redeclaring an interface appends to existing definition:
```tsx
interface MyInterface {
  name: string
}

interface MyInterface {
  phone: number
}

let variable : MyInterface = {
  name: 'MyName',
  phone: 123456789
}
```
This opens a can of worms (bugs)! In a project of significant size. Types are declared in several files, and some types are declared globally. However, if interface definition can be extended in any file, users cannot be really sure what the type is going to be at usage. Also, these bugs can be extremely challenging to locate.

On the other hand `type`s can only be created once:
```tsx
// Error: Duplicate identifier 'MyType'.
type MyType = {
  name: string
}

type MyType = {
    phone: number
}
```
Mutability of `interface`s is a *bad feature*: Value proposition of Typescript is to provide guard rails to validate types of variables in your program. Utility of Typescript is compromised if a programmer cannot be sure of what the type of interface is going to be at usage.

### 2. `interface` has unusual syntax
`type`s naturally extend the syntax of declaring variables in JavaScript while `interface`s have their own syntax which causes needless complexity.
 
```tsx
// Variable creation rule
// Construct Name = Value; 
var x = 1;
let y = 2;
const z = 3;

// Types creation rule
// Construct Name = Value; 
type MyType = string | number;


// Interface creation rule
// Construct Name {Value}; 🤔
interface MyInterface {
  name: string
}
```

### 3. `extends` on double duty

`extends` in Typescript has dual purpose:

- Extending an interface: More properties can be added to an `interface` using `extends` keyword.

```tsx
interface Animal {
  name: string
}

interface Bear extends Animal {
  honey: boolean
}
```

- Conditional type checking: For inputs to a `Generic` `extends` keyword is used to validate type at usage. Additionally, for conditional types `extends` keyword functions as a condition checker for a type being subset of another type.

```ts
const firstChar = <T extends string>(input: T) => {
  return input[0];
}

// Works!!
firstChar('abc')

// Error: Argument of type 'string[]' is not assignable to parameter of type 'string'.
firstChar(['abc'])
```

The dual usage for keyword `extends` is a source of lots of confusion. It makes it difficult for new users to adapt advanced TypeScript features.
However, we can do better! By **not** using `interface` at all we can remove this confusion as `extends` will be left with only one usage.

*PS: Special thanks to Iván Ovejero for writing [TypeScript and Set Theory](https://ivov.dev/notes/typescript-and-set-theory)*
### 4. `interface` only works with objects
Now what's up with that 🤷‍♂️. In my opinion this is the origin of problem. `interface` was designed to make it easier to work with objects, which resulted in creation of two almost similar features and endless conversation of "type vs interface". 
Software languages, libraries and frameworks follow principles of evolution. Like in any evolutionary system many species and initiatives take place to address specific needs and fill certain gaps. 
However, not all initiatives successfully manage to address real problems, and sometimes can have detrimental effects on overall structure of program. Unfortunately, unsuccessful experiments cannot be removed from a language due to backwards compatibility.

> It is rarely possible for standards committees to remove imperfections from a language because doing so would cause the breakage of all of the bad programs that depend on those bad parts.

*Douglas Crockford*

But we as developers can separate *good parts* from *bad parts* and only use *good parts* to make our softwares great!