Generics

function identity<T> (foo: T): T {
  return foo;
}

let s = identity<string>('foo');

Working on a collection:

function uniq<T> (items: T[]): T[] {
  return [...new Set(items)];
}

Advanced uses

🚀 Object and property constraints (key of):

//                    "key" must extend a key of "obj" 
//                      ↓
function getProperty<T, K extends keyof T> (obj: T, key: K) {
  return obj[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, 'a'); // for statically created objects only of course
getProperty(x, 'e'); // will trigger a warning

🚀 Class types for factories:

//              Type of Klass
//              ↓
function create<T> (Klass: {new(): T;}, name: string): T {
  return new Klass();
}

create(Dog, 'Fido');
create(Cat, 'Tabby');

For a factory method one can define the allowed class types:

function createVehicle<T extends Vehicle> (Klass: {new(): T;}, passengerCount: number): T {
  return new Klass();
}

const car = createVehicle(Car, 5);
const airplane = createVehicle(Airplane, 396);