keyof T is the union of property keys known on T. For Book with title:string and pages:number, keyof Book is “title” | “pages”. T[K] is an indexed-access type: it describes the value at key K, not an array position.
A generic getter can preserve the relationship: get<T, K extends keyof T>(record: T, key: K): T[K]. Read this left to right: choose a record type, choose one of its keys, and return the type belonging to that key. With key “pages”, the result is number; with “title”, it is string.
This differs from accepting key:string and returning string|number for every call. A precise relationship gives the caller useful information without an assertion. It still cannot prove unknown external key text belongs to the allowed set; validate that separately.
TypeScript’s typeof type query can derive a type from an existing local value, as in type Book = typeof book. That is a compile-time use of typeof, different from the runtime string returned by typeof book. Use named aliases when they make the domain clearer.
Predict, run, and explain
Write the output and trace the important state changes before checking it. Then run the program. Use Check types first; execution is allowed only when the real compiler accepts the source.
function get<T, K extends keyof T>(record: T, key: K): T[K] {
return record[key];
}
const book = { title: "Types", pages: 120 };
console.log(get(book, "title").toUpperCase());
console.log(get(book, "pages").toFixed(0));Enable JavaScript to edit and type-check this example.
Check your prediction
TYPES
120 Read the compiler error
The generic constraint ties this key to real fields of this record.
function get<T, K extends keyof T>(record: T, key: K): T[K] {
return record[key];
}
console.log(get({ title: "Types", pages: 120 }, "duration"));Enable JavaScript to edit and type-check this example.
Check your diagnosis
Use a supported key or deliberately transform the record. No assertion can create the missing property.
Make the selected key determine the result type
A dynamic string and a known property key carry different evidence. K extends keyof T restricts the input key to names present on T; returning T[K] preserves the value type associated with the chosen key. A broad string|number return would throw away that relationship.
This helper does not validate arbitrary key text from a URL or form. The caller must narrow that input before using it as a known key. Also keep type-level indexed access separate from ordinary array indexing, where a position may be absent.
function get<T, K extends keyof T>(value: T, key: K): T[K] {
return value[key];
}
const record = { title: "Types", pages: 120 };
const title = get(record, "title");
const pages = get(record, "pages");
console.log(title.toUpperCase());
console.log(pages + 1);Enable JavaScript to edit and type-check this example.
Check your prediction
TYPES
121 The two calls produce different static result types from the same helper. This lets each caller use type-appropriate operations without a cast.
const record = { title: "Types", pages: 0 };
type Key = keyof typeof record;
function read(key: Key): string | number {
return record[key];
}
console.log(read("pages"));
console.log(typeof read("title"));Enable JavaScript to edit and type-check this example.
Check your prediction
0
string The non-generic read intentionally returns the whole value union because its parameter is the whole key union. Compare that with the per-call relationship in get before choosing an API shape.
Try the rule on new inputs
Call get with every real key, then a misspelled key. Explain why a caller variable typed as string needs additional evidence. Do not assert unknown external text as keyof T without checking it.
Your turn
keyof & Indexed Types: practise
Write the generic get helper and use it with a task having label:string and done:boolean. Print Review and false. Attempting key “missing” should be rejected.
// The key type must depend on T, not be an unrelated string.Enable JavaScript to edit and type-check this example.
Hint 1: the idea
Return the indexed value type rather than any.
Hint 2: a first step
Introduce K extends keyof T and return T[K].
Show one solution
function get<T, K extends keyof T>(record: T, key: K): T[K] {
return record[key];
}
const task = { label: "Review", done: false };
console.log(get(task, "label"));
console.log(get(task, "done"));Enable JavaScript to edit and type-check this example.
Review
falseExplain why the implementation meets the stated contract. Which part is enforced by the language or checker, and which part needs behavioral evidence?
Change it and test it
Try calling a string method on get(task,“done”) and read the diagnostic. Pass a union key and explain why the result is a union of possible property types. Do not assert arbitrary input text to keyof merely to silence an error.
Completion is saved in this browser only. It does not measure mastery.