I’ve hit type vs interface confusion multiple times and read dozens of posts finally spent more time today to understand and make some sense out of it. Thought to make a notes of differences based on my understanding.
- Type is short for
type alias
in typescript. - Usually type and interfaces are used interchangeably but there are subtle differences.
- Before TS 4.2 when complex
type aliases
were created and if error occurs the compiler error messages used to be misleading where the exact error occurred compared to interfaces, but it’s fixed in TS version >4.2. - People tend to use interface for objects since it’s more natural while reading compared to type aliases which creates confusion.
1// seems more like a variable and creates confusion2type Color = {3 primary100: string4 primary200: string5}67// seems more natural that it is defining type8interface Color {9 primary100: string10 primary200: string11}
- Interfaces are easy to merge.
- This is is useful for adding missing type information on 3rd party libraries. If you are authoring a library and want to allow this capability, then interfaces are the way to go.
1interface Color {2 primary100: string3 primary200: string4}56interface Color {7 primary300: string8}910// let's see how it works in type aliases11type ColorBase = {12 primary100: string13 primary200: string14}1516type ColorExtra = {17 primary300: string18}1920type Color = ColorBase & ColorExtra2122const color: Color = {23 primary100: '#fff',24 primary200: '#ffa',25 primary300: '#ffb',26}
- For functions from a readability perspective type alias may work out better
1type GetBrandColors = () => string[];23interface GetBrandColors {4 () => string[];5}67const getBrandColors: GetBrandColors = () => ['primary', 'secondary']
- Whether you’ve chosen a
type
orinterface
the way we use it with a class is the same
1type Size = {2 size: string3};45interface Milkshake {6 name: string;7 price: number;8 getIngredients(): string[];9}1011class Order implements Size, Milkshake {12 // Size13 size = 'large';1415 // Milkshake16 name = 'Vanilla';17 price = 399;18 getIngredients() {19 return ['vanilla', 'ice'];20 }21}
- Type aliases can represent primitive types, but interfaces can’t. Interfaces are restricted to an object type.
1type Primary100 = string23// literally can't work since the consumer of this type will now have to be of object form.45interface Primary100 {6 value: string7}89// the below will throw an error as it's expecting object of the form colorPrimary.value10const colorprimary100: Primary100 = '#fff'1112// let's see anaother example with arrays13type Colors = string[];1415interface Colors {16 [index: number]: string;17}
- Type aliases can represent tuple types, but interfaces can’t.
1type Point = [number, number];
- Type aliases can use computed properties. The
in
keyword can be used to iterate over all of the items in an union of keys
1type Props = "variant" | "title"23type Button = {4 [key in Props]: string5}67interface Button {8 // errors out as we can only use "primitive types" in computed(dynamic) keys9 [key in Props]: string10}1112const button: Button = {13 variant: "primary",14 title: "Click Me!"15}
Conclusion
There’s no silver bullet as to always use type alias
or always use interface
, it depends case by case and depends what do you want to achieve in each case. 🤷🏻♂️
If you like this then don’t forget to
🐤 Share
🔔 Subscribe
➡️ Follow me on Twitter