Generics
Generic functions and classes compile once per declaration. Each type parameter becomes one 64-bit word that knows its own type (a number, string, boolean, null, undefined or object reference), or takes its constraint's layout when it has one (T extends HasId reads x.id like any object). Calls convert values at the boundary between the declaration's erased signature and tsc's resolved one.
ts
// Generic functions and classes. Type parameters are erased: each declaration compiles once.
function firstOr<T>(xs: T[], fallback: T): T {
return xs[0] ?? fallback;
}
class Stack<T> {
items: T[] = [];
push(x: T): void {
this.items.push(x);
}
pop(): T | undefined {
return this.items.pop();
}
size(): number {
return this.items.length;
}
}
interface HasId {
id: number;
}
function maxId<T extends HasId>(xs: T[]): number {
let best = -1;
for (const x of xs) best = Math.max(best, x.id);
return best;
}
console.log(firstOr([3, 4], 0), firstOr<string>([], "empty"));
const s = new Stack<string>();
s.push("a");
s.push("b");
console.log(s.pop(), s.size());
console.log(
maxId([
{ id: 4, name: "x" },
{ id: 9, name: "y" },
]),
);text
3 empty
b 1
9Limits today
- A type argument that does not fit in one word, such as an array, a
Mapor a function, is rejected (CS1242):firstOr<number[]>(...)fails. Wrap it in an object ({ items: xs }) or write a non-generic function. Specialization (monomorphization) is planned as an optimization. - Type-level computation (conditional, mapped and indexed-access types,
keyof) is rejected (CS1243); write the resulting type out. - Generic code cannot construct its type parameter (
new () => T, CS1244); pass a factory function.
Next: Closures.