带有函数的 Typescript 中的映射类型
Mapped Types in Typescript with functions
我在使用映射类型时遇到了一些问题。
我正在尝试键入一个组成 redux "selectors" 的函数(本质上只是 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 中的错误)
你的问题其实很简单。 inferredSelectorCreator
接受类型为 T
的剩余参数,但是当你调用时,你用整个数组调用 inferredSelectorCreator
,而不展开它 (inferredSelectorCreator(selectors)
) 这意味着 T
将被推断为 [[Selector<string, string>, Selector<string, number>]]
而不是 [Selector<string, string>, Selector<string, number>]
.
如果您使用价差,您会得到预期的结果:
const bazz = inferredSelectorCreator(...selectors)
我在使用映射类型时遇到了一些问题。
我正在尝试键入一个组成 redux "selectors" 的函数(本质上只是 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 中的错误)
你的问题其实很简单。 inferredSelectorCreator
接受类型为 T
的剩余参数,但是当你调用时,你用整个数组调用 inferredSelectorCreator
,而不展开它 (inferredSelectorCreator(selectors)
) 这意味着 T
将被推断为 [[Selector<string, string>, Selector<string, number>]]
而不是 [Selector<string, string>, Selector<string, number>]
.
如果您使用价差,您会得到预期的结果:
const bazz = inferredSelectorCreator(...selectors)