After this lesson you can
- Write a function that keeps the caller's type
- Constrain a type parameter so you can use it
- Read the common utility types without looking them up
This function works on anything and tells you nothing:
function first(items: any[]): any { return items[0]; }
A type parameter keeps the connection between what went in and what comes out:
function first<T>(items: T[]): T | undefined {
return items[0];
}
const n = first([1, 2, 3]); // number | undefined
const s = first(["a", "b"]); // string | undefined
T is not a type; it is a slot the caller fills, usually without noticing,
because TypeScript infers it from the argument.
Constraints
Inside the function you may only do what every possible T allows,
which is almost nothing. extends narrows what a caller may pass, and in
return lets you use it:
function longest<T extends { length: number }>(a: T, b: T): T {
return a.length >= b.length ? a : b;
}
longest("abc", "de"); // fine: strings have length
longest([1, 2], [3]); // fine: arrays have length
Try it
function groupBy<T, K extends string>( items: T[], key: (item: T) => K,): Record<K, T[]> { const out = {} as Record<K, T[]>; for (const item of items) { const k = key(item); (out[k] ??= []).push(item); } return out;} export function run(): Record<string, string[]> { const people = [ { name: "Nino", country: "GE" }, { name: "Ana", country: "GE" }, { name: "Luka", country: "DE" }, ]; const byCountry = groupBy(people, (p) => p.country); // byCountry.GE is known to be an array of those objects, not any. return { GE: byCountry.GE.map((p) => p.name), DE: byCountry.DE.map((p) => p.name), };}The utility types worth knowing
Partial<T>— every property optional. A patch object.Required<T>— the opposite.Pick<T, K>/Omit<T, K>— a subset of the properties.Record<K, V>— an object with keysKand valuesV.ReturnType<F>— what a function type returns.
They are all written in TypeScript itself, using the same features you have just seen. Nothing here is magic.
Try it yourself
2 visible tests · 2 hidden testsImplement longest<T extends { length: number }>(items: T[]): T,
returning the item with the greatest length. Where two items tie,
return the first one. Assume the array always has at least one item —
keep the parameter generic enough to work for strings and for arrays.
longest(["a","abc","ab"])longest(["only"])
Sign up to check the hidden tests and save your progress. Sign up