Skip to content

Commit d2721f4

Browse files
committed
Infer actual type of memoized function to enhance selector type
This allows correct inference of any fields that the memoize function may attach to its generated output function, such as `selector.memoizedResultFunc.clearCache` with `defaultMemoize`.
1 parent 5b84325 commit d2721f4

File tree

1 file changed

+39
-22
lines changed

1 file changed

+39
-22
lines changed

src/index.ts

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,17 @@ export function createSelectorCreator<
102102

103103
const dependencies = getDependencies(funcs)
104104

105-
// @ts-ignore
106-
const memoizedResultFunc = memoize(function () {
107-
recomputations++
108-
// apply arguments instead of spreading for performance.
109-
return resultFunc!.apply(null, arguments)
110-
}, ...finalMemoizeOptions)
105+
const memoizedResultFunc = memoize(
106+
function () {
107+
recomputations++
108+
// apply arguments instead of spreading for performance.
109+
return resultFunc!.apply(null, arguments)
110+
} as F,
111+
...finalMemoizeOptions
112+
)
111113

112114
// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
113-
// @ts-ignore
114-
const selector: OutputSelector<any, any, any, any> = memoize(function () {
115+
const selector = memoize(function () {
115116
const params = []
116117
const length = dependencies.length
117118

@@ -124,26 +125,40 @@ export function createSelectorCreator<
124125
// apply arguments instead of spreading for performance.
125126
lastResult = memoizedResultFunc.apply(null, params)
126127
return lastResult
128+
} as F)
129+
130+
Object.assign(selector, {
131+
resultFunc,
132+
memoizedResultFunc,
133+
dependencies,
134+
lastResult: () => lastResult,
135+
recomputations: () => recomputations,
136+
resetRecomputations: () => (recomputations = 0)
127137
})
128138

129-
selector.resultFunc = resultFunc
130-
selector.memoizedResultFunc = memoizedResultFunc
131-
selector.dependencies = dependencies
132-
selector.lastResult = () => lastResult
133-
selector.recomputations = () => recomputations
134-
selector.resetRecomputations = () => (recomputations = 0)
135139
return selector
136140
}
137141
// @ts-ignore
138-
return createSelector as CreateSelectorFunction<MemoizeOptions>
142+
return createSelector as CreateSelectorFunction<
143+
F,
144+
MemoizeFunction,
145+
MemoizeOptions
146+
>
139147
}
140148

141149
interface CreateSelectorOptions<MemoizeOptions extends unknown[]> {
142150
memoizeOptions: MemoizeOptions[0] | MemoizeOptions
143151
}
144152

145-
interface CreateSelectorFunction<MemoizeOptions extends unknown[] = unknown[]> {
146-
// Input selectors as separate inline arguments
153+
/**
154+
* An instance of createSelector, customized with a given memoize implementation
155+
*/
156+
interface CreateSelectorFunction<
157+
F extends (...args: unknown[]) => unknown,
158+
MemoizeFunction extends (func: F, ...options: any[]) => F,
159+
MemoizeOptions extends unknown[] = DropFirst<Parameters<MemoizeFunction>>
160+
> {
161+
/** Input selectors as separate inline arguments */
147162
<Selectors extends SelectorArray, Result>(
148163
...items:
149164
| [...Selectors, (...args: SelectorResultArray<Selectors>) => Result]
@@ -156,10 +171,11 @@ interface CreateSelectorFunction<MemoizeOptions extends unknown[] = unknown[]> {
156171
Selectors,
157172
Result,
158173
GetParamsFromSelectors<Selectors>,
159-
(...args: SelectorResultArray<Selectors>) => Result
174+
((...args: SelectorResultArray<Selectors>) => Result) &
175+
ReturnType<MemoizeFunction>
160176
>
161177

162-
// Input selectors as a separate array
178+
/** Input selectors as a separate array */
163179
<Selectors extends SelectorArray, Result>(
164180
selectors: [...Selectors],
165181
combiner: (...args: SelectorResultArray<Selectors>) => Result,
@@ -168,7 +184,8 @@ interface CreateSelectorFunction<MemoizeOptions extends unknown[] = unknown[]> {
168184
Selectors,
169185
Result,
170186
GetParamsFromSelectors<Selectors>,
171-
(...args: SelectorResultArray<Selectors>) => Result
187+
((...args: SelectorResultArray<Selectors>) => Result) &
188+
ReturnType<MemoizeFunction>
172189
>
173190
}
174191

@@ -180,7 +197,7 @@ type SelectorsObject = { [key: string]: (...args: any[]) => any }
180197
export interface StructuredSelectorCreator {
181198
<SelectorMap extends SelectorsObject>(
182199
selectorMap: SelectorMap,
183-
selectorCreator?: CreateSelectorFunction<any>
200+
selectorCreator?: CreateSelectorFunction<any, any, any>
184201
): (
185202
state: SelectorMap[keyof SelectorMap] extends (
186203
state: infer State
@@ -193,7 +210,7 @@ export interface StructuredSelectorCreator {
193210

194211
<State, Result = State>(
195212
selectors: { [K in keyof Result]: Selector<State, Result[K], never> },
196-
selectorCreator?: CreateSelectorFunction<any>
213+
selectorCreator?: CreateSelectorFunction<any, any, any>
197214
): Selector<State, Result, never>
198215
}
199216

0 commit comments

Comments
 (0)