машинописный расширенный дженерик не распространяется почему? - PullRequest
0 голосов
/ 20 декабря 2018

Сталкивался с ситуацией, которая озадачивает меня.Вот выдержка из кода:

type TInputs<A> = A[] | Iterable<A> | Record<string, A>

type TTest = <A, Src extends TInputs<A>>(src: Src) => (x: A) => A

declare const arr: number[]
declare const t: TTest

t (arr) // infered as const t: <{}, number[]>(src: number[]) => (x: {}) => {}
// expected const t: <number, number[]>(src: number[]) => (x: number) => number

Я не понимаю, почему A не сохранено ?какая-либо причина, почему он выводится как {} в этом случае?
И помимо понимания, как пройти этот вопрос?

Заранее спасибо за любой ответ
Seb

1 Ответ

0 голосов
/ 20 декабря 2018

Компилятор TypeScript не будет использовать общее ограничение в качестве позиции вывода.См. этот похожий вопрос GitHub для обсуждения этого вопроса.Это означает, что, хотя t(arr) приводит к выводу Src как number[], результирующее ограничение number[] extends A[] не может использоваться для вывода A.И поскольку ничто другое не может быть использовано для вывода A, логический вывод завершается неудачно с пустым типом «Я сдаюсь» {}.

Чтобы исправить это ... вам, вероятно, на самом деле не нужны два типапараметры.Если вы хотите, чтобы A всегда был типом элемента массива Src, вы можете просто получить этот тип элемента, выполнив lookup из Src '* number -index тип свойства, то есть: Src[number] вместо A:

type TTest = <Src extends any[]>(src: Src) => (x: Src[number]) => Src[number]

declare const arr: number[]
declare const t: TTest
t(arr)  // const t: <number[]>(src: number[]) => (x: number) => number

Похоже, это работает для меня.Надеюсь, это поможет.Удачи!


ОБНОВЛЕНИЕ

Учитывая ваши новые типы, можно использовать условный тип и infer, чтобы получить A из Src, например:

type AFromSrc<Src extends TInputs<any>> = Src extends TInputs<infer A> ? A : never;
type TTest = <Src extends TInputs<any>>(src: Src) => 
  (x: AFromSrc<Src>) => AFromSrc<Src>

Это также должно работать, пока компилятор может выводить A из TInputs<A>.Это зависит от того, насколько TInputs<> достаточно прозрачен для алгоритма вывода.Вы должны проверить, работает ли он для вас.Если нет, возможно, вам придется быть умнее.

Но если он работает , то вы можете использовать следующую, более простую сигнатуру:

type TTest = <A>(src: TInputs<A>) => (x: A) => A

То есть сохранить A и вычислить Srcот него.Это не включает условных типов, но ожидает, что компилятор сможет вывести A из значения типа TInputs<A>.Если это возможно, отлично.Если нет, вам нужно будет использовать первую подпись и пользовательский AFromSrc, который поможет компилятору определить A.

Хорошо, еще раз удачи.

...