ObjectEntries
Завдання
Реалізуйте типізовану версію Object.entries
. Наприклад:
interface Model {
name: string;
age: number;
locations: string[] | null;
}
type modelEntries = ObjectEntries<Model>;
// ['name', string] | ['age', number] | ['locations', string[] | null];
Розв’язок
Дивлячись на проблему, ідея полягає в тому, щоб використати
Типи зіставлення
аби перебрати кожен ключ в об’єкті та згенерувати для них [key, typeof key]
.
type ObjectEntries<T> = { [P in keyof T]: [P, T[P]] };
// { key: [key, typeof key], ... }
А щоб перетворити згенерований тип в об’єднання, ми просто додамо keyof T
у
кінці.
type ObjectEntries<T> = { [P in keyof T]: [P, T[P]] }[keyof T];
// [key, typeof key] | ...
Отже, як додавання keyof T
генерує об’єднання? Ну, скажімо, у вас є об’єкт:
const obj = {
foo: "bar",
};
Щоб отримати доступ до властивості foo
, ми можемо використовувати оператор .
(obj.foo
) або квадратні дужки (obj["foo"]
).
У нашому рішенні вище ми використовуємо той самий трюк. Оскільки keyof T
може
бути будь-яким із ключів, присутніх у T
, TypeScript генерує всі можливі
результати та перетворює їх на об’єднання.
Повертаючись до нашої проблеми, зауважте, як пройшли деякі тести. Уважніше розглянувши тести, які не пройшли, ми зрозуміємо, що:
- Усі необов’язкові ключі потрібно перетворити на обов’язкові. Ми можемо зробити це за допомогою модифікатора.
- Оскільки тип
Partial
додає undefined до типу, ми повинні опрацювати це.
type HandleUndefined<F, S extends keyof F> = F[S] extends infer R | undefined
? R
: F[S];
type ObjectEntries<T> = {
[P in keyof T]-?: [P, HandleUndefined<T, P>];
}[keyof T];
Коментарі