Functions

The simplest example: let inc = (x: number, y: number = 1): number => x + y;

It's fairly simple to define array parameters:

  let baptize = (familyName: string, ...names: string[]): string => [familyName, ...names].join(' ');
  //            ↑                                           ↑        ↑
  //           input                                     output     implementation

Alternate signatures

Treat this as a lightweight overloading: you can't define multiple functions with the same name, but you can define multiple interfaces for one function.

Then of course it's up to you to see if the input quacks or barks. In a "real" typed language this would not be needed, but typescript is just sugar on top of javascript (albeit sweet and helpful sugar).

function getHeight (element: HTMLElement): number; // signature A
function getHeight (element: string): number; // signature B
function getHeight (element: any): number { // this is not part of the "valid" overload list
  let node: HTMLElement;
  if (typeof element === 'string') { // we still have to poke the duck
    node = document.querySelector(element);
  } else {
    node = element;
  }
  return node.getBoundingClientRect().height;
}

to use the above function:

❗ Notice how the function "technically" accepts any type - both signatures are just type helpers and will be stripped away.

Defining context (explicit this)

One may enforce an expected calling context for a function:

interface User {
  age: number;
  department: string;
}

interface Users {
  [name: string]: User;
}

let users: Users = {
  john: { age: 30, department: 'management' },
  jack: { age: 26, department: 'backend development' },
  jill: { age: 34, department: 'human resources' }
};

function getUser (this: Users, name: string = 'jill') {
  return this[name];
}