Skip to content

Commit 8172075

Browse files
committed
type fetcher
1 parent f3680f7 commit 8172075

12 files changed

+423
-166
lines changed

infinite/index.ts

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import { useRef, useState, useCallback } from 'react'
55
import useSWR, {
66
SWRConfig,
77
KeyLoader,
8-
Fetcher,
98
SWRHook,
109
MutatorCallback,
11-
Middleware
10+
Middleware,
11+
Result,
12+
ValueKey
1213
} from 'swr'
1314
import { useIsomorphicLayoutEffect } from '../src/utils/env'
1415
import { serialize } from '../src/utils/serialize'
@@ -246,20 +247,56 @@ export const infinite = ((<Data, Error>(useSWRNext: SWRHook) => (
246247
} as SWRInfiniteResponse<Data, Error>
247248
}) as unknown) as Middleware
248249

249-
type SWRInfiniteHook = <Data = any, Error = any>(
250-
...args:
251-
| readonly [KeyLoader<Data>]
252-
| readonly [KeyLoader<Data>, Fetcher<Data> | null]
253-
| readonly [
254-
KeyLoader<Data>,
255-
SWRInfiniteConfiguration<Data, Error> | undefined
256-
]
257-
| readonly [
258-
KeyLoader<Data>,
259-
Fetcher<Data> | null,
260-
SWRInfiniteConfiguration<Data, Error> | undefined
261-
]
262-
) => SWRInfiniteResponse<Data, Error>
263-
264-
export default withMiddleware(useSWR, infinite) as SWRInfiniteHook
250+
type Fetcher<Data = unknown, Args extends ValueKey = ValueKey> = Args extends
251+
| [infer R, ...infer K]
252+
| readonly [infer R, ...infer K]
253+
? (...args: [R, ...K]) => Result<Data>
254+
: Args extends string | null
255+
? (...args: [string]) => Result<Data>
256+
: Args extends Record<infer K, infer V>
257+
? (...args: [Record<K, V>]) => Result<Data>
258+
: never
259+
260+
interface SWRInfiniteHook {
261+
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
262+
args: KeyLoader<Data, Args>
263+
): SWRInfiniteResponse<Data, Error>
264+
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
265+
args: KeyLoader<Data, Args>,
266+
fn: Fetcher<Data, Args> | null
267+
): SWRInfiniteResponse<Data, Error>
268+
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
269+
args: KeyLoader<Data, Args>,
270+
config:
271+
| SWRInfiniteConfiguration<Data, Error, Args, Fetcher<Data[], Args>>
272+
| undefined
273+
): SWRInfiniteResponse<Data, Error>
274+
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
275+
args: KeyLoader<Data, Args>,
276+
fn: Fetcher<Data, Args>,
277+
config: SWRInfiniteConfiguration<Data, Error, Args, Fetcher<Data[], Args>>
278+
): SWRInfiniteResponse<Data, Error>
279+
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
280+
...args:
281+
| [KeyLoader<Data, Args>]
282+
| [KeyLoader<Data, Args>, Fetcher<Data, Args> | null]
283+
| [
284+
KeyLoader<Data, Args>,
285+
286+
287+
| SWRInfiniteConfiguration<Data, Error, Args, Fetcher<Data[], Args>>
288+
| undefined
289+
]
290+
| [
291+
KeyLoader<Data, Args>,
292+
Fetcher<Data, Args> | null,
293+
294+
295+
| SWRInfiniteConfiguration<Data, Error, Args, Fetcher<Data[], Args>>
296+
| undefined
297+
]
298+
): SWRInfiniteResponse<Data, Error>
299+
}
300+
301+
export default (withMiddleware(useSWR, infinite) as unknown) as SWRInfiniteHook
265302
export { SWRInfiniteConfiguration, SWRInfiniteResponse }

infinite/types.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { SWRConfiguration, Fetcher, SWRResponse } from 'swr'
1+
import { SWRConfiguration, Fetcher, SWRResponse, ValueKey } from 'swr'
22

33
export type SWRInfiniteConfiguration<
44
Data = any,
5-
Error = any
6-
> = SWRConfiguration<Data[], Error, Fetcher<Data[]>> & {
5+
Error = any,
6+
Args extends ValueKey = ValueKey,
7+
Fn = Fetcher<any, Args>
8+
> = SWRConfiguration<Data[], Error, Args, Fn> & {
79
initialSize?: number
810
revalidateAll?: boolean
911
persistSize?: boolean

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@
7171
"@testing-library/jest-dom": "5.14.1",
7272
"@testing-library/react": "12.0.0",
7373
"@types/react": "17.0.20",
74-
"@typescript-eslint/eslint-plugin": "4.24.0",
75-
"@typescript-eslint/parser": "4.24.0",
74+
"@typescript-eslint/eslint-plugin": "4.31.1",
75+
"@typescript-eslint/parser": "4.31.1",
7676
"bunchee": "1.7.1",
7777
"eslint": "6.6.0",
7878
"eslint-config-prettier": "6.5.0",
@@ -91,7 +91,7 @@
9191
"react-experimental": "npm:react@alpha",
9292
"rimraf": "3.0.2",
9393
"ts-jest": "27.0.3",
94-
"typescript": "3.9.10"
94+
"typescript": "4.4.3"
9595
},
9696
"peerDependencies": {
9797
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"

src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ export {
2020
SWRHook,
2121
Fetcher,
2222
MutatorCallback,
23-
Middleware
23+
Middleware,
24+
ValueKey,
25+
Result
2426
} from './types'

src/types.ts

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
11
import * as revalidateEvents from './constants/revalidate-events'
22

3-
export type Fetcher<Data> = (...args: any) => Data | Promise<Data>
3+
export type Result<T = unknown> = T | Promise<T>
4+
5+
export type Fetcher<
6+
Data = unknown,
7+
Args extends Key = Key
8+
> = Args extends (() => [infer R, ...infer K] | readonly [infer R, ...infer K])
9+
? ((...args: [R, ...K]) => Result<Data>)
10+
: Args extends [infer R, ...infer K] | readonly [infer R, ...infer K]
11+
? ((...args: [R, ...K]) => Result<Data>)
12+
: Args extends (() => string | null)
13+
? (...args: [string]) => Result<Data>
14+
: Args extends string | null
15+
? (...args: [string]) => Result<Data>
16+
: Args extends () => Record<infer K, infer V>
17+
? (...args: [Record<K, V>]) => Result<Data>
18+
: Args extends Record<infer K, infer V>
19+
? (...args: [Record<K, V>]) => Result<Data>
20+
: never
421

522
// Configuration types that are only used internally, not exposed to the user.
623
export interface InternalConfiguration {
@@ -11,7 +28,8 @@ export interface InternalConfiguration {
1128
export interface PublicConfiguration<
1229
Data = any,
1330
Error = any,
14-
Fn extends Fetcher<Data> = Fetcher<Data>
31+
Args extends Key = Key,
32+
Fn = Fetcher<Data, Args>
1533
> {
1634
errorRetryInterval: number
1735
errorRetryCount?: number
@@ -35,22 +53,22 @@ export interface PublicConfiguration<
3553
isPaused: () => boolean
3654
onLoadingSlow: (
3755
key: string,
38-
config: Readonly<PublicConfiguration<Data, Error>>
56+
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
3957
) => void
4058
onSuccess: (
4159
data: Data,
4260
key: string,
43-
config: Readonly<PublicConfiguration<Data, Error>>
61+
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
4462
) => void
4563
onError: (
4664
err: Error,
4765
key: string,
48-
config: Readonly<PublicConfiguration<Data, Error>>
66+
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
4967
) => void
5068
onErrorRetry: (
5169
err: Error,
5270
key: string,
53-
config: Readonly<PublicConfiguration<Data, Error>>,
71+
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>,
5472
revalidate: Revalidator,
5573
revalidateOpts: Required<RevalidatorOptions>
5674
) => void
@@ -67,29 +85,51 @@ export type ConfigOptions = {
6785
initFocus: (callback: () => void) => (() => void) | void
6886
initReconnect: (callback: () => void) => (() => void) | void
6987
}
70-
71-
export type SWRHook = <Data = any, Error = any>(
72-
...args:
73-
| readonly [Key]
74-
| readonly [Key, Fetcher<Data> | null]
75-
| readonly [Key, SWRConfiguration<Data, Error> | undefined]
76-
| readonly [
77-
Key,
78-
Fetcher<Data> | null,
79-
SWRConfiguration<Data, Error> | undefined
80-
]
81-
) => SWRResponse<Data, Error>
88+
export interface SWRHook {
89+
<Data = any, Error = any, Args extends Key = Key>(args: Args): SWRResponse<
90+
Data,
91+
Error
92+
>
93+
<Data = any, Error = any, Args extends Key = Key>(
94+
args: Args,
95+
fn: Fetcher<Data, Args> | null
96+
): SWRResponse<Data, Error>
97+
<Data = any, Error = any, Args extends Key = Key>(
98+
args: Args,
99+
config: SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>> | undefined
100+
): SWRResponse<Data, Error>
101+
<Data = any, Error = any, Args extends Key = Key>(
102+
args: Args,
103+
fn: Fetcher<Data, Args>,
104+
config: SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>>
105+
): SWRResponse<Data, Error>
106+
<Data = any, Error = any, Args extends Key = Key>(
107+
...args:
108+
| [Args]
109+
| [Args, Fetcher<Data, Args> | null]
110+
| [
111+
Args,
112+
SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>> | undefined
113+
]
114+
| [
115+
Args,
116+
Fetcher<Data, Key> | null,
117+
SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>>
118+
]
119+
): SWRResponse<Data, Error>
120+
}
82121

83122
// Middlewares guarantee that a SWRHook receives a key, fetcher, and config as the argument
84123
type SWRHookWithMiddleware = <Data = any, Error = any>(
85124
key: Key,
86-
fetcher: Fetcher<Data> | null,
125+
fetcher: Fetcher<Data, Key> | null,
87126
config: SWRConfiguration<Data, Error>
88127
) => SWRResponse<Data, Error>
89128

90129
export type Middleware = (useSWRNext: SWRHook) => SWRHookWithMiddleware
91-
92-
export type ValueKey = string | any[] | object | null
130+
export type TupleKey = [any, ...unknown[]] | readonly [any, ...unknown[]]
131+
export type ValueKey = string | null | TupleKey | Record<any, any>
132+
export type Key = ValueKey | (() => ValueKey)
93133

94134
export type MutatorCallback<Data = any> = (
95135
currentValue?: Data
@@ -142,10 +182,9 @@ export type KeyedMutator<Data> = (
142182
export type SWRConfiguration<
143183
Data = any,
144184
Error = any,
145-
Fn extends Fetcher<Data> = Fetcher<Data>
146-
> = Partial<PublicConfiguration<Data, Error, Fn>>
147-
148-
export type Key = ValueKey | (() => ValueKey)
185+
Args extends Key = Key,
186+
Fn = Fetcher<any, Args>
187+
> = Partial<PublicConfiguration<Data, Error, Args, Fn>>
149188

150189
export interface SWRResponse<Data, Error> {
151190
data?: Data
@@ -154,9 +193,10 @@ export interface SWRResponse<Data, Error> {
154193
isValidating: boolean
155194
}
156195

157-
export type KeyLoader<Data = any> =
158-
| ((index: number, previousPageData: Data | null) => ValueKey)
196+
export type KeyLoader<Data = any, Args extends ValueKey = ValueKey> =
197+
| ((index: number, previousPageData: Data | null) => Args)
159198
| null
199+
160200
export interface RevalidatorOptions {
161201
retryCount?: number
162202
dedupe?: boolean

src/use-swr.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ export const useSWRHandler = <Data = any, Error = any>(
175175

176176
// Start the request and keep the timestamp.
177177
CONCURRENT_PROMISES_TS[key] = startAt = getTimestamp()
178-
newData = await (CONCURRENT_PROMISES[key] = fn.apply(fn, fnArgs))
178+
// @ts-ignore FIXME When September ends
179+
newData = await (CONCURRENT_PROMISES[key] = fn(...fnArgs))
179180

180181
setTimeout(() => {
181182
// CONCURRENT_PROMISES_TS[key] maybe be `undefined` or a number.

src/utils/normalize-args.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import { Key, Fetcher, SWRConfiguration } from '../types'
44

55
export const normalize = <KeyType = Key, Data = any>(
66
args:
7-
| readonly [KeyType]
8-
| readonly [KeyType, Fetcher<Data> | null]
9-
| readonly [KeyType, SWRConfiguration | undefined]
10-
| readonly [KeyType, Fetcher<Data> | null, SWRConfiguration | undefined]
7+
| [KeyType]
8+
| [KeyType, Fetcher<Data> | null]
9+
| [KeyType, SWRConfiguration | undefined]
10+
| [KeyType, Fetcher<Data> | null, SWRConfiguration | undefined]
1111
): [KeyType, Fetcher<Data> | null, Partial<SWRConfiguration<Data>>] => {
1212
return isFunction(args[1])
1313
? [args[0], args[1], args[2] || {}]

src/utils/serialize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { isFunction } from './helper'
33

44
import { Key } from '../types'
55

6-
export const serialize = (key: Key): [string, any, string, string] => {
6+
export const serialize = (key: Key): [string, any[], string, string] => {
77
if (isFunction(key)) {
88
try {
99
key = key()

src/utils/with-middleware.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ export const withMiddleware = (
99
): SWRHook => {
1010
return <Data = any, Error = any>(
1111
...args:
12-
| readonly [Key]
13-
| readonly [Key, Fetcher<Data> | null]
14-
| readonly [Key, SWRConfiguration | undefined]
15-
| readonly [Key, Fetcher<Data> | null, SWRConfiguration | undefined]
12+
| [Key]
13+
| [Key, Fetcher<Data> | null]
14+
| [Key, SWRConfiguration | undefined]
15+
| [Key, Fetcher<Data> | null, SWRConfiguration | undefined]
1616
) => {
1717
const [key, fn, config] = normalize(args)
1818
config.use = (config.use || []).concat(middleware)

0 commit comments

Comments
 (0)