Generics

The term "generics” refers to the ability to create a component that can work across multiple types rather than just one.

We will use a type variable, which is a special kind of variable that works on types rather than values.

function identity<Type>(arg: Type): Type {
	return arg;
}
let output = identity<string>("hello, this is the arg");
or, 
let output = identity("hello, this is the arg");

This will be used to store the types of arguments passed. If we use "any” here, we’ll lose the actual type of argument.

Generic interface

interface GenericIdentityFn<Type> {
  (arg: Type): Type;
}
function identity<Type>(arg: Type): Type {
  return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;

At runtime, there’s only one slot per static variable. So generic type won’t work for it.

Generic Constraints:

interface LengthWise {
	length: number;
}
function identityWithLengthLog<Type extends LengthWise>(arg: Type): Type {
	console.log(arg.length);
	return arg;
}

Referring to a class type by its constructor function:

class ZooKeeper {
	nameTag: string = "Hagrid";
}
class Animal {
	numOfLegs: number;
}
class Lion extends Animal {
	keeper: Zookeeper = new ZooKeeper();
}
function createInstance<A extends Animal>(constructor: new () -> A): A {
	return constructor();
}
console.log(createInstance(Lion).keeper.nameTag);

keyof type operator:

The keyofoperator takes an object type and produces a string or numeric literal union of its keys. The following type P is the same type as “x” | “y”

type Point = { x: number; y: number };
type P = keyof Point;

JavaScript object keys are always coerced to a string, so obj[0]is always the same as obj["0"]

typeof operator:

TypeScript intentionally limits the sorts of expressions you can use typeof on.

Specifically, it’s only legal to use typeof on identifiers (i.e. variable names) or their properties. This helps avoid the confusing trap of writing code you think is executing, but isn’t: