Пересечение рекуррентного типа Typescript - PullRequest
2 голосов
/ 10 октября 2019

Я попытался определить определение типа для повторяющегося пересечения , чтобы добиться такого поведения:

type merged = Merged<[{a: string}, {b: string}, ...]>

должно быть {a: string} & {b: string} & ...

Я определил некоторыеУтилиты типов, такие как Head и Tail, чтобы иметь возможность работать с переменным числом типов ввода, и им удалось определить повторяющееся объединение, но не удалось добиться того же для пересечения: (

type Head<T extends any[]> = T[0]
type Tail<T extends any[]> =
((...args: T) => any) extends ((_arg0: any, ...rest: infer R) => any) ? R : never

type United<T extends any[]> = {
  0: Head<T>
  1: United<Tail<T>>
}[ T extends ([] | [any])
  ? 0
  : 0 | 1
]

type Merged<T extends any[]> = {
  0: Head<T>
  1: Merged<Tail<T>>
}[T extends ([] | [any])
  ? 0
  : 0 & 1
]

type a = {a: string}
type b = {b: string}
type c = {c: string}

type head = Head<[a, b, c, d]>       // {a: string} OK
type tail = Tail<[a, b, c, d]>       // [b, c]      OK
type united = United<[a, b, c, d]>   // a | b | c   OK
type merged = Merged<[a, b, c, d]>   // unknown     Not good

Я долженчто-то не так на некоторых базовых внутренних объектах TypeScript, но я не знаю , почему он работал в случае объединения, а не в случае пересечения ?

Как это можно исправить?

1 Ответ

2 голосов
/ 10 октября 2019

Я бы не стал делать что-либо рекурсивное здесь, тем более что такого рода рекурсивное индексирование не поддерживается .

Кроме того, пересечения ключевых типов почти всегда будут разрушаться до чего-то never -подобного, поэтому получат never или unknown или что-то нежелательное из этого. То есть индексированный доступ не обязательно распределяется по пересечениям:

type OOPS = { a: a, b: b }["a" & "b"] // never! not a & b

Вместо этого я бы использовал предлагаемое решение здесь , чтобы взять объединение и преобразовать его в пересечение:

type Merged<A extends readonly any[]> =
    A[number] extends infer U ?
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ?
    I : never : never;


type a = { a: string }
type b = { b: string }
type c = { c: string }
type d = { d: string }
type merged = Merged<[a, b, c, d]>   // a & b & c & d

Это должно сработать для вас. Надеюсь, это поможет;удачи!

Ссылка на код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...