Skip to content

Latest commit

 

History

History
262 lines (197 loc) · 8.59 KB

type-vs-interface.md

File metadata and controls

262 lines (197 loc) · 8.59 KB

Item 13: Know the Differences Between type and interface

Things to Remember

  • Understand the differences and similarities between type and interface.
  • Know how to write the same types using either syntax.
  • Be aware of declaration merging for interface and type inlining for type.
  • For projects without an established style, prefer interface to type for object types.

Code Samples

type TState = {
  name: string;
  capital: string;
};

💻 playground


interface IState {
  name: string;
  capital: string;
}

💻 playground


const wyoming: TState = {
  name: 'Wyoming',
  capital: 'Cheyenne',
  population: 578_000
  // ~~~~~~~ Object literal may only specify known properties,
  //         and 'population' does not exist in type 'TState'
};

💻 playground


type TDict = { [key: string]: string };
interface IDict {
  [key: string]: string;
}

💻 playground


type TFn = (x: number) => string;
interface IFn {
  (x: number): string;
}
type TFnAlt = {
  (x: number): string;
};

const toStrT: TFn = x => '' + x;  // OK
const toStrI: IFn = x => '' + x;  // OK
const toStrTAlt: TFnAlt = x => '' + x;  // OK

💻 playground


type TBox<T> = {
  value: T;
};
interface IBox<T> {
  value: T;
}

💻 playground


interface IStateWithPop extends TState {
  population: number;
}
type TStateWithPop = IState & { population: number; };

💻 playground


class StateT implements TState {
  name: string = '';
  capital: string = '';
}
class StateI implements IState {
  name: string = '';
  capital: string = '';
}

💻 playground


type AorB = 'a' | 'b';

💻 playground


type Input = { /* ... */ };
type Output = { /* ... */ };
interface VariableMap {
  [name: string]: Input | Output;
}

💻 playground


type NamedVariable = (Input | Output) & { name: string };

💻 playground


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

type TPerson = Person & { age: number; };  // no error, unusable type

interface IPerson extends Person {
  //      ~~~~~~~ Interface 'IPerson' incorrectly extends interface 'Person'.
  //                Types of property 'age' are incompatible.
  //                  Type 'number' is not assignable to type 'string'.
  age: number;
}

💻 playground


type Pair = [a: number, b: number];
type StringList = string[];
type NamedNums = [string, ...number[]];

💻 playground


interface IState {
  name: string;
  capital: string;
}
interface IState {
  population: number;
}
const wyoming: IState = {
  name: 'Wyoming',
  capital: 'Cheyenne',
  population: 578_000
};  // OK

💻 playground


// lib.es5.d.ts
interface Array<T> {
  /** Gets or sets the length of the array. */
  length: number;
  // ...
  [n: number]: T;
}

💻 playground


// lib.es2015.core.d.ts
interface Array<T> {
  /** Returns the index of the first element in the array where predicate... */
  findIndex(
    predicate: (value: T, index: number, obj: T[]) => unknown,
    thisArg?: any
  ): number;

  // ... also find, fill, copyWithin
}

💻 playground


export function getHummer() {
  type Hummingbird = { name: string; weightGrams: number; };
  const ruby: Hummingbird = { name: 'Ruby-throated', weightGrams: 3.4 };
  return ruby;
};

const rubyThroat = getHummer();
//    ^? const rubyThroat: Hummingbird

💻 playground


// get-hummer.d.ts
export declare function getHummer(): {
  name: string;
  weightGrams: number;
};

💻 playground


export function getHummer() {
  //            ~~~~~~~~~
  // Return type of exported function has or is using private name 'Hummingbird'.
  interface Hummingbird { name: string; weightGrams: number; };
  const bee: Hummingbird = { name: 'Bee Hummingbird', weightGrams: 2.3 };
  return bee;
};

💻 playground