Отображенные типы в Typescript с функциями - PullRequest
0 голосов
/ 25 января 2019

У меня небольшие проблемы с использованием сопоставленных типов.

Я пытаюсь набрать функцию, которая составляет редукторные "селекторы" (которые по сути являются просто функциями из A => B)

API, к которому я стремлюсь, в основном:

const bar = composeSelectors([
  (s: string) => s.length,
  (s: string) => s.trim(),
])

bar // should be (s: string) => [number, string]

Вот что я получил до сих пор:

type Selector<A, Z> = (a:A) => Z
type Selected<T> = T extends Selector<any, infer U> ? U : never;
type MappedSelector<S, T> = Selector<S, { [Y in keyof T]: Selected<T[Y]> }>

const selectedNumber: Selected<Selector<string, number>> = null as any
selectedNumber // is number

const baz: MappedSelector<string, [Selector<string, number>, Selector<string, string>]> = null as any
baz  // is Selector<string, [number, string]> !!!

Кажется, это работает хорошо, пока я не попытаюсь использовать MappedSelector в функции:

type InferableMappedSelector<S> = <T extends any[]>(...values: T) => MappedSelector<S, T>
function createInferredSelector<S>(): InferableMappedSelector<S> {...}
const inferredSelectorCreator = createInferredSelector<string>()


const fooSelector: Selector<string, number> = s => s.length;
const barSelector: Selector<string, string> = s => s.trim();
const selectors: [Selector<string, string>, Selector<string, number>] = [barSelector, fooSelector]

const baz = inferredSelectorCreator(selectors)
baz // is Selector<string, [never]>, not Selector<string, [number, string]>

Я также пробовал:

type InferableMappedSelector<S> = <T extends Selector<string, any>[]>(...values: T) => MappedSelector<S, T>

const baz = inferredSelectorCreator(selectors)
// doesn't typecheck due to: 
// Argument of type '[Selector<string, string>, Selector<string, number>]' is not assignable to // parameter of type 'Selector<string, any>'.
//   Type '[Selector<string, string>, Selector<string, number>]' provides no match for the signature // '(a: string): any'.

(этот последний бит кажется ошибкой в ​​TS)

1 Ответ

0 голосов
/ 25 января 2019

Ваша проблема на самом деле довольно проста.inferredSelectorCreator принимает параметр отдыха типа T, но когда вы вызываете, вы вызываете inferredSelectorCreator со всем массивом, не распространяя его (inferredSelectorCreator(selectors)), это означает, что T будет выведено в [[Selector<string, string>, Selector<string, number>]] вместо[Selector<string, string>, Selector<string, number>].

Если вы используете спред, вы получите ожидаемый результат:

const bazz = inferredSelectorCreator(...selectors)
...