Implement the type version of ```Object.entries``` Master advanced TypeScript type manipulation in this medium-level challenge on TypeScriptPro.
In this medium-level challenge, you'll implement the type-level version of Object.entries, which converts an object type into a union of key-value tuple pairs while correctly handling optional and undefined properties.
Implement the type version of Object.entries
For example
interface Model {
name: string;
age: number;
locations: string[] | null;
}
type modelEntries = ObjectEntries<Model> // ['name', string] | ['age', number] | ['locations', string[] | null];Change the following code to make the test cases pass (no type check errors).
interface Model {
name: string
age: number
locations: string[] | null
}
type ModelEntries =
| ['name', string]
| ['age', number]
| ['locations', string[] | null]
type cases = [
Expect<Equal<ObjectEntries<Model>, ModelEntries>>,
Expect<Equal<ObjectEntries<Partial<Model>>, ModelEntries>>,
Expect<Equal<ObjectEntries<{ key?: undefined }>, ['key', undefined]>>,
Expect<Equal<ObjectEntries<{ key: undefined }>, ['key', undefined]>>,
Expect<
Equal<
ObjectEntries<{ key: string | undefined }>,
['key', string | undefined]
>
>,
]
Unlock 102+ medium, hard, and extreme challenges to master advanced TypeScript.
One-time payment. Lifetime access.
type ObjectEntries<T> = {
[K in keyof Required<T>]: [K, Required<T>[K] extends never ? undefined : Required<T>[K]];
}[keyof T];How it works:
T with Required<T> to remove all optional modifiers, which prevents undefined from being automatically added to the value types of optional properties (e.g., Partial<Model> would otherwise add undefined to every value)K maps to a tuple [K, ValueType], representing one entryRequired<T>[K] to get the clean value without the optional undefined injection, but checks for never and replaces it with undefined to handle edge cases like { key?: undefined }[keyof T] at the end converts the mapped object into a union of all its values, producing the final union of entry tupleskeyof T (not keyof Required<T>) ensures only the original keys are included in the resultAn alternative approach using a distributive conditional:
type RemoveUndefined<T> = [T] extends [undefined] ? T : Exclude<T, undefined>;
type ObjectEntries<T> = {
[K in keyof T]-?: [K, RemoveUndefined<T[K]>];
}[keyof T];This challenge helps you understand mapped types, optional property handling, and indexed access types, and how to apply these concepts in real-world scenarios.
This challenge is originally from here.