Differences between Types alias and Interface in TypeScript.

TS is basically a language built on JavaScript to make the latter strongly typed.
Strongly types mean you adhere to a strict way of writing code, which gives more security or type safety, and reduces errors, although it involves writing more code, you are definitely going to have more productivity.TS being a superset of JS provides the same functionalities and features as JS itself and compiles to JS which the browser understands. It enforces the use of type safety which allows us to define the type of data in our code base.

In TS, we have 2 major ways of passing data types and they are represented by simple object-based paradigms. One is to declare using Types Aliases and the other method is to use Interface according to the docs.

Now let's discuss the differences:-

  1. Import/Export:- There is a difference in the way we import and export Type aliases and Interfaces.

    In Types aliases, import/export can be done by adding type as a suffix after import and then the type name we wish to import i.e using the type-only imports and exports method while in Interface, we import using the module import/export method also used in JS. Modules are executed within their local scope and not on global scope except we have them exported

     // Using named export/import
     // TypeScript 3.8 added a new syntax for type-only imports and exports
     //Type alias
     type Person = {
       name: string;
       age: number;
     };
     export type { Person };
     import type { Person } from "./some-module.js";
    
     // Interfaces
     export interface President {
       name: string;
       country: string;
     }
     import { President } from './another-file';
    
  2. Declaration merging:- Interface is less flexible, uses the extends keyword, and is more of a syntax while Type aliases is more flexible, uses intersection or & symbol, and can be addressed as a collection of data type. According to the docs,

    "Declaration merging means that the compiler merges two separate declarations declared with the same name into a single definition. This merged definition has the features of both of the original declarations. Any number of declarations can be merged; it’s not limited to just two declarations.

    interface Person {
      name: string
      age: number
    }
    interface SecondPerson extends Person {
      gender: string
      profession: string
    }
    // SecondPerson automatically inherit the properties of Person.
    

    For Type

     type Person = {
       name: string
       age: number
     }
     type NewPerson = Person & {
       gender: string
       profession: string
     }
     //NewPerson inherits the properties of Person and can also have new properties added to it.
    
  3. In merging declaration, Interface, due to its flexibility can be re-opened and a new value can be added, but this is impossible to achieve using a Type aliases. Interface allows this action to be carried out without the use of the extends keywords.

     interface carsData {
         name: string;
         desc: string;
     }
     interface carsData {
         price: number;
         inStock?: boolean;
         quantity: number;
     }
     const stock: carsData = {
        name: "Mercedes Benz",
        desc:"A car that has advanced and high tech-driving features.",
        price: 80000,
        inStock: true,
        quantity: 2
     }
    
     type phone = {
         name: string
     }
     // You cannot add new variables in the same way
     type phone = {
         inStock: string
     }
    
  4. Object Shape:- Interface can only be used to declare the shape of an object but cannot be used to rename the primitives(string, number, boolean), which is a concept allowed with the use of Type aliad. TS depends heavily on the structure of the data being set, this allows for the extra safety guarantee it provides and flexibility. With Type aliases, these primitive values can be set, but with Interfaces, the values have to be structurally placed in an object.

     type Country = string;
     type Age = number;
    
     // This will also throw an error
     interface X = string;
     interface State extends string  {
      }
    
     // This is the acceptable method 
     interface Town {
         value: string
     }
     type City = {
         value: string
     }
    
  5. Union:- Type aliases allows the use of Union, which simply implies the combination of more than two or more primitives. In the use of a union, a value can be the combination of a string, number, or/and a boolean. Type aliases allows for the use of a union which is termed union types, this is impossible using Interface.

     type myDetails =  string | number | boolean 
     // This is wrong 
     interface myDetails =  string | number | boolean
    

    Error message

Conclusion:

Lastly, you may be wondering with this knowledge, which is the best option for your JS or ReactJS project, well, it all depends on what you are trying to achieve but check out this part of the docs.

Interface and Type aliases form an integral part of defining the structure of your data, they help to ensure type safety and conformity, especially when working on a large codebase. It is highly recommended for large JS projects with several contributors in the team.

If you are a React/NextJS developer, and you want to start using TS, I will recommend this cheat sheet which has in-depth tutorials and cheat about how to ensure you have minimal errors in your code.