keyof operator takes an object type and produces a literal union of its keys. It acts as the type-level equivalent of JavaScript’s runtime Object.keys() function, enabling type-safe object property access and dynamic schema transformations.1. What is keyof?#
Given any object type T, keyof T queries the structural shape of T and returns a union of all allowed property key names:
interface Point3D {
x: number;
y: number;
z: number;
}
// 🟢 Extract the keys of Point3D as a literal union
type Point3DKeys = keyof Point3D;
// Inferred Type: "x" | "y" | "z"
let validAxis: Point3DKeys = "x"; // Valid
validAxis = "z"; // Valid
// ❌ Compiler Error: Type '"w"' is not assignable to type 'Point3DKeys'.
// validAxis = "w";
2. Type-Safe Property Accessors (getValue)#
Without keyof, writing a generic property getter function in JavaScript requires resorting to any or loose string types, risking runtime undefined property bugs:
// ❌ UNSAFE: Allows passing non-existent string keys!
function getPropertyUnsafe(obj: any, key: string) {
return obj[key];
}By combining keyof with Generics (<T, K extends keyof T>), we force the caller to supply a key that definitely exists on the object, and we automatically infer the exact return type T[K]:
// 🟢 TYPE-SAFE: 'K' is constrained to valid keys of 'T', return type is T[K]
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = {
id: "usr_991",
username: "rachmat",
age: 30,
isVerified: true,
};
// 1. 'key' parameter is restricted to "id" | "username" | "age" | "isVerified"
// 2. Return type is automatically inferred as 'string'!
const username = getProperty(user, "username");
// Return type is automatically inferred as 'number'!
const age = getProperty(user, "age");
// ❌ Compiler Error: Argument of type '"email"' is not assignable to parameter of type '"id" | "username" | "age" | "isVerified"'.
// getProperty(user, "email");
3. keyof on Index Signatures#
How does keyof behave when applied to an object type that contains an Index Signature?
interface StringDictionary {
[key: string]: boolean;
}
type DictKeys = keyof StringDictionary;
// Inferred Type: string | number
Why does keyof return string | number?#
In JavaScript, object keys are automatically coerced to strings at runtime. If you execute dict[100], JavaScript coerces 100 to "100".
Therefore, TypeScript permits indexing a [key: string] dictionary with both string and number types!
interface NumberDictionary {
[key: number]: string;
}
type NumDictKeys = keyof NumberDictionary;
// Inferred Type: number (ONLY number, because strings cannot be implicitly converted to numbers!)
4. keyof any (The Universal Key Constraint)#
What happens if you run keyof any?
In JavaScript, valid object key types are strictly limited to string, number, and symbol. Therefore, keyof any evaluates to that exact primitive union:
type ValidKey = keyof any;
// Inferred Type: string | number | symbol
This is frequently used as a generic constraint when defining custom record types:
// Constrain K to valid object keys (string | number | symbol)
type CustomRecord<K extends keyof any, V> = {
[P in K]: V;
};5. Combining keyof with Indexed Access (T[keyof T])#
By pairing keyof T with Indexed Access (T[...]), you can dynamically extract a union of all property value types inside an interface:
interface HTTPResponse {
statusCode: number;
statusText: string;
isOk: boolean;
headers: Record<string, string>;
}
// 🟢 Extract the union of ALL property value types:
type ResponseValueTypes = HTTPResponse[keyof HTTPResponse];
// Inferred Type: number | string | boolean | Record<string, string>
How this resolves:#
keyof HTTPResponseresolves to"statusCode" | "statusText" | "isOk" | "headers".HTTPResponse["statusCode" | "statusText" | "isOk" | "headers"]looks up all 4 properties simultaneously.- Resolves to the union:
number | string | boolean | Record<string, string>.
Summary & Next Steps#
In this episode:
- We queried object types with
keyof Tto extract literal key unions. - We built a type-safe generic property getter
getProperty<T, K extends keyof T>(obj, key): T[K]. - We analyzed
keyofon index signatures ([key: string]$\to$string | number). - We verified
keyof any$\to$string | number | symbol. - We combined
keyof Twith Indexed Access (T[keyof T]) to extract unions of property value types.
In Episode 28: The typeof Operator, we will explore how to query types directly from runtime JavaScript values!

