Встроенные частичные дженерики не являются гибкими, на помощь приходят дженерики PartialByKeys.
Добро пожаловать в серию Mastering TypeScript, в которой десятки статей. Чтобы помочь читателям лучше закрепить свои знания о TypeScript, я выбрал несколько десятков заданий из репозитория type-challenges на Github, чтобы выполнить задание вместе с вами.
- Требования к типу: реализация встроенного типа утилиты Pick‹T, K›
- Проблемы с типом: реализация встроенного служебного типа Omit‹T, K›
- Требования к типу: реализация типа утилиты RequiredByKeys‹T, K›
Испытание
Реализуйте общий PartialByKeys<T, K>
, который принимает два аргумента типа T
и K
.
K
укажите набор свойств T
, которые должны быть необязательными. Когда K
не указан, он должен сделать все свойства необязательными, как и обычный Partial<T>
.
Например:
interface User { name: string age: number address: string } type UserPartialName = PartialByKeys<User, 'name'> // { name?:string; age:number; address:string }
Решение
Наша задача типа состоит в том, чтобы реализовать универсальный PartialByKeys<T, K>
. Когда K
не предоставляется, он должен сделать все свойства необязательными, как и обычный Partial<T>
. Итак, давайте сначала разберемся, что делает Partial<T>
generic.
Partial
<T>
Создает тип со всеми свойствами Type
, установленными как необязательные.
Partial<T>
— это тип встроенной утилиты TypeScript, который определен в файле typescript/lib/lib.es5.d.ts
:
/** * Make all properties in T optional. * typescript/lib/lib.es5.d.ts */ type Partial<T> = { [P in keyof T]?: T[P]; };
Универсальный Partial<T>
использует сопоставленный тип TypeScript внутри, и его синтаксис выглядит следующим образом:
Где P in K
похож на оператор JavaScript for...in
, который используется для перебора всех типов в типе K
, и переменная типа T
, которая используется для представления любого типа в TypeScript.
Вы также можете использовать дополнительные модификаторы только для чтения и вопросительный знак (?) в процессе сопоставления. Соответствующие модификаторы добавляются и удаляются путем добавления префиксов плюс (+) и минус (-). По умолчанию используется знак "плюс", если префикс не добавлен.
После введения соответствующих знаний о сопоставленных типах идея реализации универсального PartialByKeys<T, K>
очень проста.
Как видно из приведенного выше рисунка, нам нужно только выбрать свойства, связанные с K, установить их как необязательные и сгенерировать новый тип объекта, затем создать другой тип объекта на основе оставшихся свойств и наконец, используйте оператор &
для преобразования двух вышеуказанных типов объектов в новый тип объектов.
Если вы хотите узнать больше о типах перекрестков, прочитайте эту статью.
Полный код
Наконец, давайте посмотрим на полный код:
TypeScript 4.1 позволяет нам переназначать ключи в сопоставленных типах с помощью предложения as. Его синтаксис следующий:
type MappedTypeWithNewKeys<T> = { [K in keyof T as NewKeyType]: T[K] // ^^^^^^^^^^^^^ // New Syntax! }
где тип NewKeyType должен быть подтипом типа объединения string | number | symbol
. В процессе переназначения ключей мы можем фильтровать ключи, возвращая тип never.
Роль универсального Merge
заключается в объединении типов объектов. Помимо вышеперечисленных решений, есть более лаконичный способ.
type PartialByKeys<T, K = keyof T> = Merge< { [P in keyof T as P extends K ? P : never]?: T[P] } & Pick<T, Exclude<keyof T, K> >
В приведенном выше коде мы используем встроенный тип утилиты TypeScript Pick
, если вы хотите узнать больше об этом универсальном типе, вы можете прочитать следующую статью:
Основное знание, связанное с этой задачей, — это сопоставленные типы в TypeScript. Если вы хотите узнать больше о сопоставленных типах, прочитайте следующую статью:
Если у вас есть другие решения, вы можете дать мне сообщение. Вы также можете подписаться на меня в Medium или Twitter, чтобы узнать больше о TS и JS!
Ресурсы
Создавайте приложения с повторно используемыми компонентами, такими как Lego.
Инструмент с открытым исходным кодом Bit помогает более чем 250 000 разработчиков создавать приложения с компонентами.
Превратите любой пользовательский интерфейс, функцию или страницу в компонент многократного использования — и поделитесь им со своими приложениями. Легче сотрудничать и строить быстрее.
Разделите приложения на компоненты, чтобы упростить разработку приложений, и наслаждайтесь наилучшими возможностями для рабочих процессов, которые вы хотите: