Generics: the ability to abstract types
Generic Function
function identity<T>(value: T): T {
return value;
}
// Automatic structure checks
function get<T, K extends keyof T>(p: T, key: K): any {
return p[key]
}
Generic Interfaces
interface Identities<V, W> {
id1: V,
id2: W
}
function identities<T, U> (arg1: T, arg2: U): Identities<T, U> {
console.log(arg1 + ": " + typeof (arg1));
console.log(arg2 + ": " + typeof (arg2));
let identities: Identities<T, U> = {
id1: arg1,
id2: arg2
};
return identities;
}
Generic classes
abstract class Animal {
handle() { throw new Error("Not implemented") }
}
class Horse extends Animal{
color: string
handle() {
console.log("Riding the horse...")
}
}
class Dog extends Animal{
name: string
handle() {
console.log("Feeding the dog...")
}
}
class Handler<T extends Animal> {
animal: T
constructor(animal: T) {
this.animal = animal
}
handle() {
this.animal.handle()
}
}
class DogHandler extends Handler<Dog> {}
class HorseHandler extends Handler<Horse> {}
Variadic Tuples
type MyTuple<T extends unknown[]> = [string, string, ...T, number]
let myList:MyTuple<[boolean, number]> = ["Fernando", "Doglio", true, 3, 37]
let myList:MyTuple<[number, number, number]> = ["Fernando", "Doglio", 1,2,3,4]
usage
Typing Dynamic Objects and Subsets with Generics
type Pick<T> = { [K in keyof T]: T[K] };
function pick<T> (obj: T, keys: (keyof T)[]): Pick<T> {
throw "not yet implemented"
}
type Pick<T, U extends keyof T> = { [K in U]: T[K] };
function pick<T, U extends keyof T> (obj: T, keys: U[]): Pick<T, U> {
throw "not yet implemented"
}
keyof syntax
// some article type
type Article = {
title: string,
id: number,
...
}
// some key of article
type Key = keyof Article;
// some array of keys of article
type KeyArray = (keyof Article)[];
Typing the return type based on keys provided
const articleTitle = pick(article, ["title"]);
type resolved = typeof articleTitle;