Reading Generic Types
Array<T>, identity functions, Promise<T>, Record, Partial — reading TypeScript generics in plain English
TypeScript generics vocabulary
- T (type parameter) — a placeholder replaced with a concrete type at the call/usage site; TypeScript infers it from arguments
- Array<T> = T[] — equivalent; an array whose elements are all of type T
- Promise<T> — a Promise that resolves to T;
awaitunwraps it to T - Record<K, V> — object type with keys K and values V; equivalent to
{ [key: K]: V } - Partial<T> — all properties of T become optional; useful for patch/update operations
Question 0 of 5
What does Array<T> mean in TypeScript?function first<T>(arr: Array<T>): T | undefined {
return arr[0];
}
const n = first([1, 2, 3]); // n: number | undefined
const s = first(["a", "b"]); // s: string | undefined
- Generic type — a type that accepts type parameters, written as
Type<T> - Type parameter T — a placeholder for a specific type; conventional names are T (type), K (key), V (value), E (element)
- Type inference — TypeScript infers T from the argument:
first([1, 2, 3])infers T asnumber - Array<T> = T[] — both are equivalent syntax for an array of T
first would need to return any, losing type safety. Generics preserve type information through the function.Read this generic function signature. What is T and what does the function guarantee?function identity<T>(arg: T): T {
return arg;
}
const x = identity(42); // x: number
const y = identity("hello"); // y: string
const z = identity({ id: 1 }); // z: { id: number }
- T flows through — the type variable T captures the input type and "flows" to the return type
- Without generics:
function identity(arg: any): any— works but loses type information; caller getsany - With generics:
identity(42)gives TypeScript enough to know x isnumber, notany - Constraint — you can constrain T:
<T extends string>means T must be string or a subtype
What does Promise<User[]> return from this async function?interface User {
id: number;
name: string;
}
async function fetchUsers(): Promise<User[]> {
const res = await fetch("/api/users");
return res.json();
}
- Promise<T> — a generic type; T is the resolved value type
- async function — always returns a Promise; the declared return type is what the Promise resolves to
- await fetchUsers() — unwraps the Promise, giving you
User[]directly - res.json() returns
Promise<any>— TypeScript trusts the declared return type annotation to type the result asUser[]
Promise<void> (no value), Promise<User | null> (nullable), Promise<{ data: User[]; total: number }> (object).What is Record<string, number>?const scores: Record<string, number> = {
alice: 95,
bob: 87,
charlie: 92,
};
function getScore(name: string): number | undefined {
return scores[name];
}
- Record<string, number> =
{ [key: string]: number }— any string key, number value - Record<'a' | 'b', string> — only allows keys 'a' and 'b' (literal union as key type)
- Built-in implementation:
type Record<K extends keyof any, V> = { [P in K]: V; } - Use cases — lookup tables, caches, config maps, count maps (e.g.,
Record<string, number>for word frequencies)
.get(), .set().Read this usage of Partial<User>. What does the utility type do?interface User {
id: number;
name: string;
email: string;
role: "admin" | "user";
}
function updateUser(id: number, changes: Partial<User>): void {
// changes can have any subset of User properties
}
updateUser(1, { name: "Alice" }); // valid
updateUser(1, { email: "a@b.com" }); // valid
updateUser(1, { name: "A", role: "admin" }); // valid
- Partial<User> =
{ id?: number; name?: string; email?: string; role?: ... } - Implementation:
type Partial<T> = { [P in keyof T]?: T[P]; }— maps over all keys, adding? - Use cases — PATCH endpoints, React state updates, configuration overrides, Object.assign merges
- Related types:
Required<T>— makes all properties required;Readonly<T>— makes all properties readonly
Partial<Config> and merges with defaults using { ...defaults, ...overrides }.