Skip to content

Commit 3c3864f

Browse files
committed
type useSWR fetcher
add comments about implementation add type test scripts for other middleware
1 parent fb3d8b4 commit 3c3864f

11 files changed

+359
-124
lines changed

package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@
4646
"build:immutable": "bunchee index.ts --cwd immutable -m --no-sourcemap",
4747
"prepublishOnly": "yarn clean && yarn build",
4848
"publish-beta": "yarn publish --tag beta",
49-
"types:check": "tsc --noEmit",
49+
"types:check": "yarn types:check:core && yarn types:check:infinite && yarn types:check:immutable && yarn types:check:fetcher",
50+
"types:check:core": "tsc --noEmit",
51+
"types:check:infinite": "cd infinite && tsc --noEmit",
52+
"types:check:immutable": "cd immutable && tsc --noEmit",
53+
"types:check:fetcher": "cd test-type && tsc --noEmit",
5054
"format": "prettier --write ./**/*.{ts,tsx}",
5155
"lint": "eslint . --ext .ts,.tsx",
5256
"lint:fix": "yarn lint --fix",
@@ -74,8 +78,8 @@
7478
"@testing-library/jest-dom": "5.14.1",
7579
"@testing-library/react": "12.0.0",
7680
"@types/react": "17.0.20",
77-
"@typescript-eslint/eslint-plugin": "4.31.0",
78-
"@typescript-eslint/parser": "4.31.0",
81+
"@typescript-eslint/eslint-plugin": "4.31.1",
82+
"@typescript-eslint/parser": "4.31.1",
7983
"bunchee": "1.7.1",
8084
"eslint": "6.8.0",
8185
"eslint-config-prettier": "6.5.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: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,46 @@
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<Data = unknown, Args extends Key = Key> =
6+
/**
7+
* () => [{ foo: string }, { bar: number }] | null
8+
*
9+
* () => ( [{ foo: string }, { bar: number } ] as const | null )
10+
*/
11+
Args extends (() => readonly [...infer K] | null)
12+
? ((...args: [...K]) => Result<Data>)
13+
/**
14+
* [{ foo: string }, { bar: number } ] | null
15+
*
16+
* [{ foo: string }, { bar: number } ] as const | null
17+
*/
18+
: Args extends (readonly [...infer K])
19+
? ((...args: [...K]) => Result<Data>)
20+
/**
21+
* () => string | null
22+
* () => Record<any, any> | null
23+
*/
24+
: Args extends (() => infer T | null)
25+
? (...args: [T]) => Result<Data>
26+
/**
27+
* string | null
28+
*/
29+
: Args extends (string | null)
30+
/**
31+
* when key is Record<any, any> | null
32+
* use { foo: string, bar: number } | null as example
33+
*
34+
* the fetcher would be
35+
* (arg0: string) => any | (arg0: { foo: string, bar: number }) => any
36+
* so we add this condition to make (arg0: string) => any to be never
37+
*/
38+
? Args extends (Record<any, any> | null)
39+
? never
40+
: (...args: [string]) => Result<Data>
41+
: Args extends (infer T)
42+
? (...args: [T]) => Result<Data>
43+
: never
444

545
// Configuration types that are only used internally, not exposed to the user.
646
export interface InternalConfiguration {
@@ -11,7 +51,8 @@ export interface InternalConfiguration {
1151
export interface PublicConfiguration<
1252
Data = any,
1353
Error = any,
14-
Fn extends Fetcher<Data> = Fetcher<Data>
54+
Args extends Key = Key,
55+
Fn = Fetcher<Data, Args>
1556
> {
1657
errorRetryInterval: number
1758
errorRetryCount?: number
@@ -35,22 +76,22 @@ export interface PublicConfiguration<
3576
isPaused: () => boolean
3677
onLoadingSlow: (
3778
key: string,
38-
config: Readonly<PublicConfiguration<Data, Error>>
79+
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
3980
) => void
4081
onSuccess: (
4182
data: Data,
4283
key: string,
43-
config: Readonly<PublicConfiguration<Data, Error>>
84+
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
4485
) => void
4586
onError: (
4687
err: Error,
4788
key: string,
48-
config: Readonly<PublicConfiguration<Data, Error>>
89+
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
4990
) => void
5091
onErrorRetry: (
5192
err: Error,
5293
key: string,
53-
config: Readonly<PublicConfiguration<Data, Error>>,
94+
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>,
5495
revalidate: Revalidator,
5596
revalidateOpts: Required<RevalidatorOptions>
5697
) => void
@@ -67,29 +108,51 @@ export type ConfigOptions = {
67108
initFocus: (callback: () => void) => (() => void) | void
68109
initReconnect: (callback: () => void) => (() => void) | void
69110
}
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>
111+
export interface SWRHook {
112+
<Data = any, Error = any, Args extends Key = Key>(args: Args): SWRResponse<
113+
Data,
114+
Error
115+
>
116+
<Data = any, Error = any, Args extends Key = Key>(
117+
args: Args,
118+
fn: Fetcher<Data, Args> | null
119+
): SWRResponse<Data, Error>
120+
<Data = any, Error = any, Args extends Key = Key>(
121+
args: Args,
122+
config: SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>> | undefined
123+
): SWRResponse<Data, Error>
124+
<Data = any, Error = any, Args extends Key = Key>(
125+
args: Args,
126+
fn: Fetcher<Data, Args>,
127+
config: SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>>
128+
): SWRResponse<Data, Error>
129+
<Data = any, Error = any, Args extends Key = Key>(
130+
...args:
131+
| [Args]
132+
| [Args, Fetcher<Data, Args> | null]
133+
| [
134+
Args,
135+
SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>> | undefined
136+
]
137+
| [
138+
Args,
139+
Fetcher<Data, Key> | null,
140+
SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>>
141+
]
142+
): SWRResponse<Data, Error>
143+
}
82144

83145
// Middlewares guarantee that a SWRHook receives a key, fetcher, and config as the argument
84146
type SWRHookWithMiddleware = <Data = any, Error = any>(
85147
key: Key,
86-
fetcher: Fetcher<Data> | null,
148+
fetcher: Fetcher<Data, Key> | null,
87149
config: SWRConfiguration<Data, Error>
88150
) => SWRResponse<Data, Error>
89151

90152
export type Middleware = (useSWRNext: SWRHook) => SWRHookWithMiddleware
91-
92-
export type ValueKey = string | any[] | object | null
153+
export type TupleKey = [any, ...unknown[]] | readonly [any, ...unknown[]]
154+
export type ValueKey = string | null | TupleKey | Record<any, any>
155+
export type Key = ValueKey | (() => ValueKey)
93156

94157
export type MutatorCallback<Data = any> = (
95158
currentValue?: Data
@@ -142,10 +205,9 @@ export type KeyedMutator<Data> = (
142205
export type SWRConfiguration<
143206
Data = any,
144207
Error = any,
145-
Fn extends Fetcher<Data> = Fetcher<Data>
146-
> = Partial<PublicConfiguration<Data, Error, Fn>>
147-
148-
export type Key = ValueKey | (() => ValueKey)
208+
Args extends Key = Key,
209+
Fn = Fetcher<any, Args>
210+
> = Partial<PublicConfiguration<Data, Error, Args, Fn>>
149211

150212
export interface SWRResponse<Data, Error> {
151213
data?: Data
@@ -157,6 +219,7 @@ export interface SWRResponse<Data, Error> {
157219
export type KeyLoader<Data = any> =
158220
| ((index: number, previousPageData: Data | null) => ValueKey)
159221
| null
222+
160223
export interface RevalidatorOptions {
161224
retryCount?: number
162225
dedupe?: boolean

src/use-swr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export const useSWRHandler = <Data = any, Error = any>(
173173

174174
// Start the request and keep the timestamp.
175175
CONCURRENT_PROMISES_TS[key] = getTimestamp()
176-
CONCURRENT_PROMISES[key] = fn.apply(fn, fnArgs)
176+
CONCURRENT_PROMISES[key] = fn(...fnArgs)
177177
}
178178

179179
// Wait until the ongoing request is done. Deduplication is also

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)