Skip to content

Commit

Permalink
type fetcher
Browse files Browse the repository at this point in the history
  • Loading branch information
promer94 committed Sep 19, 2021
1 parent f3680f7 commit 8172075
Show file tree
Hide file tree
Showing 12 changed files with 423 additions and 166 deletions.
73 changes: 55 additions & 18 deletions infinite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import { useRef, useState, useCallback } from 'react'
import useSWR, {
SWRConfig,
KeyLoader,
Fetcher,
SWRHook,
MutatorCallback,
Middleware
Middleware,
Result,
ValueKey
} from 'swr'
import { useIsomorphicLayoutEffect } from '../src/utils/env'
import { serialize } from '../src/utils/serialize'
Expand Down Expand Up @@ -246,20 +247,56 @@ export const infinite = ((<Data, Error>(useSWRNext: SWRHook) => (
} as SWRInfiniteResponse<Data, Error>
}) as unknown) as Middleware

type SWRInfiniteHook = <Data = any, Error = any>(
...args:
| readonly [KeyLoader<Data>]
| readonly [KeyLoader<Data>, Fetcher<Data> | null]
| readonly [
KeyLoader<Data>,
SWRInfiniteConfiguration<Data, Error> | undefined
]
| readonly [
KeyLoader<Data>,
Fetcher<Data> | null,
SWRInfiniteConfiguration<Data, Error> | undefined
]
) => SWRInfiniteResponse<Data, Error>

export default withMiddleware(useSWR, infinite) as SWRInfiniteHook
type Fetcher<Data = unknown, Args extends ValueKey = ValueKey> = Args extends
| [infer R, ...infer K]
| readonly [infer R, ...infer K]
? (...args: [R, ...K]) => Result<Data>
: Args extends string | null
? (...args: [string]) => Result<Data>
: Args extends Record<infer K, infer V>
? (...args: [Record<K, V>]) => Result<Data>
: never

interface SWRInfiniteHook {
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
args: KeyLoader<Data, Args>
): SWRInfiniteResponse<Data, Error>
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
args: KeyLoader<Data, Args>,
fn: Fetcher<Data, Args> | null
): SWRInfiniteResponse<Data, Error>
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
args: KeyLoader<Data, Args>,
config:
| SWRInfiniteConfiguration<Data, Error, Args, Fetcher<Data[], Args>>
| undefined
): SWRInfiniteResponse<Data, Error>
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
args: KeyLoader<Data, Args>,
fn: Fetcher<Data, Args>,
config: SWRInfiniteConfiguration<Data, Error, Args, Fetcher<Data[], Args>>
): SWRInfiniteResponse<Data, Error>
<Data = any, Error = any, Args extends ValueKey = ValueKey>(
...args:
| [KeyLoader<Data, Args>]
| [KeyLoader<Data, Args>, Fetcher<Data, Args> | null]
| [
KeyLoader<Data, Args>,


| SWRInfiniteConfiguration<Data, Error, Args, Fetcher<Data[], Args>>
| undefined
]
| [
KeyLoader<Data, Args>,
Fetcher<Data, Args> | null,


| SWRInfiniteConfiguration<Data, Error, Args, Fetcher<Data[], Args>>
| undefined
]
): SWRInfiniteResponse<Data, Error>
}

export default (withMiddleware(useSWR, infinite) as unknown) as SWRInfiniteHook
export { SWRInfiniteConfiguration, SWRInfiniteResponse }
8 changes: 5 additions & 3 deletions infinite/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { SWRConfiguration, Fetcher, SWRResponse } from 'swr'
import { SWRConfiguration, Fetcher, SWRResponse, ValueKey } from 'swr'

export type SWRInfiniteConfiguration<
Data = any,
Error = any
> = SWRConfiguration<Data[], Error, Fetcher<Data[]>> & {
Error = any,
Args extends ValueKey = ValueKey,
Fn = Fetcher<any, Args>
> = SWRConfiguration<Data[], Error, Args, Fn> & {
initialSize?: number
revalidateAll?: boolean
persistSize?: boolean
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@
"@testing-library/jest-dom": "5.14.1",
"@testing-library/react": "12.0.0",
"@types/react": "17.0.20",
"@typescript-eslint/eslint-plugin": "4.24.0",
"@typescript-eslint/parser": "4.24.0",
"@typescript-eslint/eslint-plugin": "4.31.1",
"@typescript-eslint/parser": "4.31.1",
"bunchee": "1.7.1",
"eslint": "6.6.0",
"eslint-config-prettier": "6.5.0",
Expand All @@ -91,7 +91,7 @@
"react-experimental": "npm:react@alpha",
"rimraf": "3.0.2",
"ts-jest": "27.0.3",
"typescript": "3.9.10"
"typescript": "4.4.3"
},
"peerDependencies": {
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
Expand Down
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ export {
SWRHook,
Fetcher,
MutatorCallback,
Middleware
Middleware,
ValueKey,
Result
} from './types'
94 changes: 67 additions & 27 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
import * as revalidateEvents from './constants/revalidate-events'

export type Fetcher<Data> = (...args: any) => Data | Promise<Data>
export type Result<T = unknown> = T | Promise<T>

export type Fetcher<
Data = unknown,
Args extends Key = Key
> = Args extends (() => [infer R, ...infer K] | readonly [infer R, ...infer K])
? ((...args: [R, ...K]) => Result<Data>)
: Args extends [infer R, ...infer K] | readonly [infer R, ...infer K]
? ((...args: [R, ...K]) => Result<Data>)
: Args extends (() => string | null)
? (...args: [string]) => Result<Data>
: Args extends string | null
? (...args: [string]) => Result<Data>
: Args extends () => Record<infer K, infer V>
? (...args: [Record<K, V>]) => Result<Data>
: Args extends Record<infer K, infer V>
? (...args: [Record<K, V>]) => Result<Data>
: never

// Configuration types that are only used internally, not exposed to the user.
export interface InternalConfiguration {
Expand All @@ -11,7 +28,8 @@ export interface InternalConfiguration {
export interface PublicConfiguration<
Data = any,
Error = any,
Fn extends Fetcher<Data> = Fetcher<Data>
Args extends Key = Key,
Fn = Fetcher<Data, Args>
> {
errorRetryInterval: number
errorRetryCount?: number
Expand All @@ -35,22 +53,22 @@ export interface PublicConfiguration<
isPaused: () => boolean
onLoadingSlow: (
key: string,
config: Readonly<PublicConfiguration<Data, Error>>
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
) => void
onSuccess: (
data: Data,
key: string,
config: Readonly<PublicConfiguration<Data, Error>>
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
) => void
onError: (
err: Error,
key: string,
config: Readonly<PublicConfiguration<Data, Error>>
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
) => void
onErrorRetry: (
err: Error,
key: string,
config: Readonly<PublicConfiguration<Data, Error>>,
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>,
revalidate: Revalidator,
revalidateOpts: Required<RevalidatorOptions>
) => void
Expand All @@ -67,29 +85,51 @@ export type ConfigOptions = {
initFocus: (callback: () => void) => (() => void) | void
initReconnect: (callback: () => void) => (() => void) | void
}

export type SWRHook = <Data = any, Error = any>(
...args:
| readonly [Key]
| readonly [Key, Fetcher<Data> | null]
| readonly [Key, SWRConfiguration<Data, Error> | undefined]
| readonly [
Key,
Fetcher<Data> | null,
SWRConfiguration<Data, Error> | undefined
]
) => SWRResponse<Data, Error>
export interface SWRHook {
<Data = any, Error = any, Args extends Key = Key>(args: Args): SWRResponse<
Data,
Error
>
<Data = any, Error = any, Args extends Key = Key>(
args: Args,
fn: Fetcher<Data, Args> | null
): SWRResponse<Data, Error>
<Data = any, Error = any, Args extends Key = Key>(
args: Args,
config: SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>> | undefined
): SWRResponse<Data, Error>
<Data = any, Error = any, Args extends Key = Key>(
args: Args,
fn: Fetcher<Data, Args>,
config: SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>>
): SWRResponse<Data, Error>
<Data = any, Error = any, Args extends Key = Key>(
...args:
| [Args]
| [Args, Fetcher<Data, Args> | null]
| [
Args,
SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>> | undefined
]
| [
Args,
Fetcher<Data, Key> | null,
SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>>
]
): SWRResponse<Data, Error>
}

// Middlewares guarantee that a SWRHook receives a key, fetcher, and config as the argument
type SWRHookWithMiddleware = <Data = any, Error = any>(
key: Key,
fetcher: Fetcher<Data> | null,
fetcher: Fetcher<Data, Key> | null,
config: SWRConfiguration<Data, Error>
) => SWRResponse<Data, Error>

export type Middleware = (useSWRNext: SWRHook) => SWRHookWithMiddleware

export type ValueKey = string | any[] | object | null
export type TupleKey = [any, ...unknown[]] | readonly [any, ...unknown[]]
export type ValueKey = string | null | TupleKey | Record<any, any>
export type Key = ValueKey | (() => ValueKey)

export type MutatorCallback<Data = any> = (
currentValue?: Data
Expand Down Expand Up @@ -142,10 +182,9 @@ export type KeyedMutator<Data> = (
export type SWRConfiguration<
Data = any,
Error = any,
Fn extends Fetcher<Data> = Fetcher<Data>
> = Partial<PublicConfiguration<Data, Error, Fn>>

export type Key = ValueKey | (() => ValueKey)
Args extends Key = Key,
Fn = Fetcher<any, Args>
> = Partial<PublicConfiguration<Data, Error, Args, Fn>>

export interface SWRResponse<Data, Error> {
data?: Data
Expand All @@ -154,9 +193,10 @@ export interface SWRResponse<Data, Error> {
isValidating: boolean
}

export type KeyLoader<Data = any> =
| ((index: number, previousPageData: Data | null) => ValueKey)
export type KeyLoader<Data = any, Args extends ValueKey = ValueKey> =
| ((index: number, previousPageData: Data | null) => Args)
| null

export interface RevalidatorOptions {
retryCount?: number
dedupe?: boolean
Expand Down
3 changes: 2 additions & 1 deletion src/use-swr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ export const useSWRHandler = <Data = any, Error = any>(

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

setTimeout(() => {
// CONCURRENT_PROMISES_TS[key] maybe be `undefined` or a number.
Expand Down
8 changes: 4 additions & 4 deletions src/utils/normalize-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { Key, Fetcher, SWRConfiguration } from '../types'

export const normalize = <KeyType = Key, Data = any>(
args:
| readonly [KeyType]
| readonly [KeyType, Fetcher<Data> | null]
| readonly [KeyType, SWRConfiguration | undefined]
| readonly [KeyType, Fetcher<Data> | null, SWRConfiguration | undefined]
| [KeyType]
| [KeyType, Fetcher<Data> | null]
| [KeyType, SWRConfiguration | undefined]
| [KeyType, Fetcher<Data> | null, SWRConfiguration | undefined]
): [KeyType, Fetcher<Data> | null, Partial<SWRConfiguration<Data>>] => {
return isFunction(args[1])
? [args[0], args[1], args[2] || {}]
Expand Down
2 changes: 1 addition & 1 deletion src/utils/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { isFunction } from './helper'

import { Key } from '../types'

export const serialize = (key: Key): [string, any, string, string] => {
export const serialize = (key: Key): [string, any[], string, string] => {
if (isFunction(key)) {
try {
key = key()
Expand Down
8 changes: 4 additions & 4 deletions src/utils/with-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ export const withMiddleware = (
): SWRHook => {
return <Data = any, Error = any>(
...args:
| readonly [Key]
| readonly [Key, Fetcher<Data> | null]
| readonly [Key, SWRConfiguration | undefined]
| readonly [Key, Fetcher<Data> | null, SWRConfiguration | undefined]
| [Key]
| [Key, Fetcher<Data> | null]
| [Key, SWRConfiguration | undefined]
| [Key, Fetcher<Data> | null, SWRConfiguration | undefined]
) => {
const [key, fn, config] = normalize(args)
config.use = (config.use || []).concat(middleware)
Expand Down
Loading

0 comments on commit 8172075

Please sign in to comment.