Что такое utility types в TypeScript, например Partial и DeepPartial
Что проверяют
Знаете ли вы встроенные утилитные типы и понимаете ли, что они собраны из отображённых и условных типов, а не встроены магией.
Как отвечать
Утилитные типы это готовые преобразования типов из стандартной библиотеки:
- Partial<T>: все поля необязательные. Для обновлений и черновиков;
- Required<T>: наоборот, все обязательные;
- Readonly<T>: все только для чтения;
- Pick<T, K> и Omit<T, K>: взять или исключить поля;
- Record<K, V>: объект с заданными ключами и типом значений;
- ReturnType<F>, Parameters<F>, Awaited<T>: вывести тип из функции или промиса;
- Exclude<T, U>, Extract<T, U>, NonNullable<T>: работа с объединениями.
Полезно показать, что это не магия. Partial определён отображённым типом в пару строк:
type Partial<T> = { [K in keyof T]?: T[K] };DeepPartial в стандартной библиотеке нет, его пишут сами через рекурсию:
type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;Тут стоит оговориться, что наивная версия ломается на массивах, Date, Map и функциях: их тоже разберёт на поля. В настоящем коде добавляют проверки на эти типы, поэтому и в стандартную библиотеку такой тип не включили.
Где спотыкаются
Считают утилитные типы встроенными конструкциями компилятора.
Пишут DeepPartial наивно и ломают массивы и даты.
Используют Partial для входных данных API вместо валидации: тип ничего не проверяет во время выполнения.
Не знают Omit и вручную перечисляют оставшиеся поля.