Skip to main content

type-safe implementation

How to define a type-safe implementation of Object.keys()

How would you define a type-safe implementation of Object.keys() that returns an array of string keys for any given object, including objects with index signatures?

For example, given the following object:

const obj = {
foo: 'bar',
baz: 42,
[Symbol('qux')]: true
};

Note that the array of keys includes both string keys and symbol keys.


To define a type-safe implementation of Object.keys(), we can create a generic type that takes an object type as a parameter and returns an array of the keys of that object. We can use an intersection type to combine the keys of the object with the keys of any index signature on the object.

Here's an example implementation:

type Keys<T> = (keyof T)[] & (string extends keyof T ? string[] : never) & (number extends keyof T ? number[] : never) & (symbol extends keyof T ? symbol[] : never);

function keys<T extends object>(obj: T): Keys<T> {
return Object.keys(obj) as Keys<T>;
}

The Keys<T> type is defined as an intersection of three array types:

• (keyof T)[] - an array of the keys of the object T • (string extends keyof T ? string[] : never) - an array of all string indexes of the object T • (symbol extends keyof T ? symbol[] : never) - an array of all symbol indexes of the object T We use conditional types to check if T has string or symbol index signatures, and if so, add those keys to the resulting array type.

The keys() function takes an object of type T and returns an array of type Keys<T>. We use a type assertion to cast the result of Object.keys(obj) to Keys<T>, which ensures that the returned array contains all the keys of the object, including any index signatures.

With this implementation, we can use the keys() function to get a type-safe array of keys for any object, including objects with index signatures:

const obj = {
foo: 'bar',
baz: 42,
[Symbol('qux')]: true
};
const keysArray = keys(obj);
// keysArray: (typeof obj)[]

In this example, keysArray has the type ('foo' | 'baz' | symbol)[], which is a type-safe array of keys for the obj object.

👉 Read More