#typescript #typescript-generics #mapped-types
#typescript #typescript-дженерики #сопоставленные типы
Вопрос:
У меня есть type
который используется для проецирования ключей, присутствующих в T
, на общие ключи и их типы, присутствующие в U
:
type IntersectByCommonKey<T, U, V = any> = {
[K in keyof U]: K extends keyof T ?
T[K] extends V ?
U[K]
: T[K] extends object ?
IntersectByCommonKey<T[K], U[K], V>
: T[K] extends object | undefined ?
IntersectByCommonKey<T[K], U[K], V> | undefined
: never
: never
};
Ссылка IntersectByCommonKey Playground
где для каждого ключа K
в U
, если T
имеет тот же ключ K
, и если тип в K
extends V
, включает форму для этого ключа, в противном случае never
.
С типом, возвращаемым IntersectByCommonKey
я хочу удалить каждый ключ, который имеет never
тип, что означает, что он также должен справляться с вложенными Record
формами.
Удалить ключи верхнего уровня достаточно просто:
type ExcludeKeysWithTypeOf<T, V> = {
[K in keyof T]: Exclude<T[K], undefined> extends V ? never : K
}[keyof T]
type Without<T, V> = Pick<T, ExcludeKeysWithTypeOf<T, V>>;
Ссылка ExcludeKeysWithTypeOf Playground
Тем не менее, я изо всех сил пытаюсь достичь того же результата для вложенных Record
файлов, есть ли способ рекурсивно удалять ключи с типами never
?
Ответ №1:
Нам нужно выполнить рекурсивный вызов, чтобы перейти к типам вложенных записей. Вот пример решения:
type Without<T, V, WithNevers = {
[K in keyof T]: Exclude<T[K], undefined> extends V ? never
: (T[K] extends Record<string, unknown> ? Without<T[K], V> : T[K])
}> = Pick<WithNevers, {
[K in keyof WithNevers]: WithNevers[K] extends never ? never : K
}[keyof WithNevers]>
Основная идея заключается в том, что когда у нашего T[K]
будет тип записи, он снова рекурсивно вызовет себя ( Without
функция уровня типа). Весь тип будет приведен к желаемой форме, в которой каждый вложенный объект будет иметь удаленные ключи, которые мы хотели.
Весь фрагмент кода — игровая площадка
Примечание: Я переместил вычисление WithNevers
внутри списка аргументов типа, чтобы добиться лучшей читаемости. Мы также можем определить его как отдельный тип.