What is keyof
?
The keyof
operator in TypeScript is used to create a union type of all the property names (keys) of an object type. This union type can then be used to define and enforce type constraints within your code.
type KeyOfDemo = keyof { name: string; age: number }; // "name" | "age"
How does it work?
When applied to an object type, keyof
generates a union type comprising all the keys of that object's properties. This union type can be used for various purposes like indexing, type-checking, and creating more precise type definitions.
2. Practical Use Cases
Type-Safe Object Access
One of the most common use cases for keyof
is enabling type-safe object access. Consider a scenario where you have an object representing a person:
const person = {
name: "John",
age: 30,
city: "New York",
};
By using keyof
, you can create a type that ensures you only access valid properties:
type Person = typeof person;
type PersonKeys = keyof Person; // "name" | "age" | "city"
Now, you can access person
properties safely:
function getProperty(obj: Person, key: PersonKeys): any {
return obj[key];
}
const name = getProperty(person, "name"); // ✅ Type-safe
const invalid = getProperty(person, "gender"); // ❌ Compile-time error
Enforcing Property Keys
You can also use keyof
to enforce that an object contains specific keys:
function hasRequiredKeys(obj: Person, keys: ["name", "age"]): boolean {
return keys.every(key => key in obj);
}
const hasKeys = hasRequiredKeys(person, ["name", "age"]); // ✅ true
const missingKey = hasRequiredKeys(person, ["name", "gender"]); // ❌ false
Function Parameter Validation
keyof
can be a valuable tool for validating function parameters, ensuring only valid keys are accepted:
function updatePerson(obj: Person, key: PersonKeys, value: any): void {
obj[key] = value; // ✅ Type-safe
}
updatePerson(person, "age", 31); // ✅
updatePerson(person, "gender", "Male"); // ❌ Compile-time error
3. Advanced Techniques
Combining keyof
with Other Operators
You can combine keyof
with other TypeScript operators for even more powerful type definitions. For example, using keyof
with typeof
to create a mapped type:
type OptionalPerson = {
[K in keyof Person]?: Person[K];
};
Generics and keyof
Generics and keyof
can be used together to create flexible and reusable type-safe functions:
function getPropertyByKey<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const cityName = getPropertyByKey(person, "city"); // ✅ Type-safe
4. Common Pitfalls and Best Practices
Avoiding String Literals
Avoid using string literals when working with keyof
to maintain type safety:
const prop = "age";
const age = person[prop]; // ❌ No type checking
Type Narrowing
Remember that keyof
unions need to be narrowed down for conditional checks:
type KnownKeys = "name" | "age";
function isKnownKey(key: string): key is KnownKeys {
return ["name", "age"].includes(key);
}
Keyof in Libraries
When working with external libraries, be cautious about assuming property keys. Libraries might use techniques like symbol-based keys, which keyof
might not cover.
Top comments (1)
so clear