TypeScript keyof Operator
The keyof
operator in TypeScript is a powerful tool for working with object types. It extracts the keys of an object type as a union of string literals. This allows you to create type-safe code that interacts with object properties dynamically.
Let’s say you have an interface defining a user:
interface User {
id: number;
name: string;
email?: string; // Optional property
}
Using keyof
, you can create a type that represents the valid property names of User
:
type UserKey = keyof User;
UserKey
will be equivalent to the type 'id' | 'name' | 'email'
. This means any variable of type UserKey
can only hold one of those three strings. This becomes incredibly useful when you need to write functions that access object properties dynamically.
Here’s an example:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user: User = {
id: 123,
name: 'John Doe',
email: 'john.doe@example.com'
};
const userId = getProperty(user, 'id'); // userId is of type number
const userName = getProperty(user, 'name'); // userName is of type string
// The following line will cause a compile-time error because 'age' is not a key of User
// const userAge = getProperty(user, 'age');
In this example, getProperty
is a generic function that takes an object obj
of type T
and a key key
of type K
. The K extends keyof T
constraint ensures that key
is a valid property name of obj
. This provides type safety and prevents accessing non-existent properties at compile time.
Another useful application of keyof
is in creating lookup types:
interface Product {
name: string;
price: number;
description: string;
}
type ProductAttributes = {
[K in keyof Product]: string;
};
ProductAttributes
is a type that has the same keys as Product
, but all the values are strings. This can be useful when you need to transform the values of an object while maintaining its keys. For instance, if you need to represent all product attributes as strings for a search index.
The keyof
operator helps write more robust and type-safe code by ensuring that you are only working with valid property names of an object, ultimately making your TypeScript code easier to maintain and debug.