Generics
Keyof and Indexed Access
The keyof operator lets code choose a property name while keeping the result type connected.
keyof
`keyof` creates a union of the property names from an object type.
Keyof and Indexed Access
keyof.ts
Replay: real traced execution (multi-file project)
type Course = {
title: string;
minutes: number;
complete: boolean;
};
function getValue<T, K extends keyof T>(object: T, key: K): T[K] {
return object[key];
}
const field: keyof Course = "minutes";
const course: Course = { title: "Generics", minutes: 25, complete: false };
const value: Course[typeof field] = getValue<Course, typeof field>(course, field);
console.log(`${field}=${value}`);
type Course = {
title: string;
minutes: number;
complete: boolean;
};
function getValue<T, K extends keyof T>(object: T, key: K): T[K] {
return object[key];
}
const field: keyof Course = "title";
const course: Course = { title: "Generics", minutes: 25, complete: false };
const value: Course[typeof field] = getValue<Course, typeof field>(course, field);
console.log(`${field}=${value}`);
type Course = {
title: string;
minutes: number;
complete: boolean;
};
function getValue<T, K extends keyof T>(object: T, key: K): T[K] {
return object[key];
}
const field: keyof Course = "complete";
const course: Course = { title: "Generics", minutes: 25, complete: false };
const value: Course[typeof field] = getValue<Course, typeof field>(course, field);
console.log(`${field}=${value}`);
field ← minutes, course ← [object Object]
8 return object[key];9}1011const field→ minutes: keyof Course = "minutes"; //@field="title", "complete"12const course→ [object Object]: Course = { title: "Generics", minutes: 25, complete: false };13const value: Course[typeof field] = getValue<Course, typeof field>(course[object Object], fieldminutes);function getValue<T, K extends keyof T>(object: T, key: K): T[K]
4 complete: boolean;5};67function getValue<T, K extends keyof T>(object[object Object]: T, keyminutes: K): T[K] {8 return object[key]25;9}value ← 25
11const field: keyof Course = "minutes"; //@field="title", "complete"12const course: Course = { title: "Generics", minutes: 25, complete: false };13const value→ 25: Course[typeof field] = getValue<Course, typeof field>(course[object Object], fieldminutes);1415console.log(`${fieldminutes}=${value25}`);outputminutes=25
field ← title, course ← [object Object]
8 return object[key];9}1011const field→ title: keyof Course = "title";12const course→ [object Object]: Course = { title: "Generics", minutes: 25, complete: false };13const value: Course[typeof field] = getValue<Course, typeof field>(course[object Object], fieldtitle);function getValue<T, K extends keyof T>(object: T, key: K): T[K]
4 complete: boolean;5};67function getValue<T, K extends keyof T>(object[object Object]: T, keytitle: K): T[K] {8 return object[key]Generics;9}value ← Generics
11const field: keyof Course = "title";12const course: Course = { title: "Generics", minutes: 25, complete: false };13const value→ Generics: Course[typeof field] = getValue<Course, typeof field>(course[object Object], fieldtitle);1415console.log(`${fieldtitle}=${valueGenerics}`);outputtitle=Generics
field ← complete, course ← [object Object]
8 return object[key];9}1011const field→ complete: keyof Course = "complete";12const course→ [object Object]: Course = { title: "Generics", minutes: 25, complete: false };13const value: Course[typeof field] = getValue<Course, typeof field>(course[object Object], fieldcomplete);function getValue<T, K extends keyof T>(object: T, key: K): T[K]
4 complete: boolean;5};67function getValue<T, K extends keyof T>(object[object Object]: T, keycomplete: K): T[K] {8 return object[key]false;9}value ← false
11const field: keyof Course = "complete";12const course: Course = { title: "Generics", minutes: 25, complete: false };13const value→ false: Course[typeof field] = getValue<Course, typeof field>(course[object Object], fieldcomplete);1415console.log(`${fieldcomplete}=${valuefalse}`);outputcomplete=false
Follow the Key
fieldstarts asminutes.courseholdstitle="Generics",minutes=25, andcomplete=false.getValue(course, field)reads the property named byfield.- With
field="minutes", the value is25. - The program prints
minutes=25. | field | course value read | printed output | | --- | --- | --- | | minutes | 25 | minutes=25 | | title | Generics | title=Generics | | complete | false | complete=false |
Exercise: keyof.ts
Reproduce minutes=25, then use field title and complete to predict title=Generics and complete=false.