Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Refine type interfaces #1496

Merged
merged 4 commits into from
Sep 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 13 additions & 41 deletions infinite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,38 @@
import { useRef, useState, useCallback } from 'react'
import useSWR, {
SWRConfig,
KeyLoader,
Fetcher,
SWRHook,
MutatorCallback,
Middleware,
ValueKey,
Result
Arguments
} from 'swr'
import { useIsomorphicLayoutEffect } from '../src/utils/env'
import { serialize } from '../src/utils/serialize'
import { isUndefined, isFunction, UNDEFINED } from '../src/utils/helper'
import { withMiddleware } from '../src/utils/with-middleware'
import { SWRInfiniteConfiguration, SWRInfiniteResponse } from './types'
import {
SWRInfiniteConfiguration,
SWRInfiniteResponse,
SWRInfiniteHook,
InfiniteKeyLoader,
InfiniteFetcher
} from './types'

const INFINITE_PREFIX = '$inf$'

const getFirstPageKey = (getKey: KeyLoader) => {
const getFirstPageKey = (getKey: InfiniteKeyLoader) => {
return serialize(getKey ? getKey(0, null) : null)[0]
}

export const unstable_serialize = (getKey: KeyLoader) => {
export const unstable_serialize = (getKey: InfiniteKeyLoader) => {
return INFINITE_PREFIX + getFirstPageKey(getKey)
}

export const infinite = ((<Data, Error, Args extends ValueKey>(
export const infinite = ((<Data, Error, Args extends Arguments>(
useSWRNext: SWRHook
) => (
getKey: KeyLoader<Args>,
getKey: InfiniteKeyLoader<Args>,
fn: Fetcher<Data> | null,
config: typeof SWRConfig.default & SWRInfiniteConfiguration<Data, Error, Args>
): SWRInfiniteResponse<Data, Error> => {
Expand Down Expand Up @@ -250,37 +254,5 @@ export const infinite = ((<Data, Error, Args extends ValueKey>(
} as SWRInfiniteResponse<Data, Error>
}) as unknown) as Middleware

export type InfiniteFetcher<
Args extends ValueKey = ValueKey,
Data = any
> = Args extends (readonly [...infer K])
? ((...args: [...K]) => Result<Data>)
: Args extends null
? never
: Args extends (infer T)
? (...args: [T]) => Result<Data>
: never

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

export default withMiddleware(useSWR, infinite) as SWRInfiniteHook
export { SWRInfiniteConfiguration, SWRInfiniteResponse }
export { SWRInfiniteConfiguration, SWRInfiniteResponse, InfiniteFetcher }
46 changes: 43 additions & 3 deletions infinite/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import { SWRConfiguration, Fetcher, SWRResponse, ValueKey } from 'swr'
import { SWRConfiguration, SWRResponse, Arguments } from 'swr'

type FetcherResponse<Data = unknown> = Data | Promise<Data>

export type InfiniteFetcher<
Args extends Arguments = Arguments,
Data = any
> = Args extends (readonly [...infer K])
? ((...args: [...K]) => FetcherResponse<Data>)
: Args extends null
? never
: Args extends (infer T)
? (...args: [T]) => FetcherResponse<Data>
: never

export type InfiniteKeyLoader<Args extends Arguments = Arguments> =
| ((index: number, previousPageData: any | null) => Args)
| null

export type SWRInfiniteConfiguration<
Data = any,
Error = any,
Args extends ValueKey = ValueKey
> = SWRConfiguration<Data[], Error, Args, Fetcher<Data[], Args>> & {
Args extends Arguments = Arguments
> = SWRConfiguration<Data[], Error, Args> & {
initialSize?: number
revalidateAll?: boolean
persistSize?: boolean
Expand All @@ -17,3 +34,26 @@ export interface SWRInfiniteResponse<Data = any, Error = any>
size: number | ((_size: number) => number)
) => Promise<Data[] | undefined>
}

export interface SWRInfiniteHook {
<Data = any, Error = any, SWRInfiniteArguments extends Arguments = Arguments>(
getKey: InfiniteKeyLoader<SWRInfiniteArguments>
): SWRInfiniteResponse<Data, Error>
<Data = any, Error = any, SWRInfiniteArguments extends Arguments = Arguments>(
getKey: InfiniteKeyLoader<SWRInfiniteArguments>,
fetcher: InfiniteFetcher<SWRInfiniteArguments, Data> | null
): SWRInfiniteResponse<Data, Error>
<Data = any, Error = any, SWRInfiniteArguments extends Arguments = Arguments>(
getKey: InfiniteKeyLoader<SWRInfiniteArguments>,
config:
| SWRInfiniteConfiguration<Data, Error, SWRInfiniteArguments>
| undefined
): SWRInfiniteResponse<Data, Error>
<Data = any, Error = any, SWRInfiniteArguments extends Arguments = Arguments>(
getKey: InfiniteKeyLoader<SWRInfiniteArguments>,
fetcher: InfiniteFetcher<SWRInfiniteArguments, Data> | null,
config:
| SWRInfiniteConfiguration<Data, Error, SWRInfiniteArguments>
| undefined
): SWRInfiniteResponse<Data, Error>
}
3 changes: 1 addition & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ export {
Fetcher,
MutatorCallback,
Middleware,
ValueKey,
Result
Arguments
} from './types'
95 changes: 45 additions & 50 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
import * as revalidateEvents from './constants/revalidate-events'

export type Result<T = unknown> = T | Promise<T>
export type FetcherResponse<Data = unknown> = Data | Promise<Data>

export type Fetcher<Data = unknown, Args extends Key = Key> =
export type Fetcher<Data = unknown, SWRKey extends Key = Key> =
/**
* () => [{ foo: string }, { bar: number }] | null
*
* () => ( [{ foo: string }, { bar: number } ] as const | null )
*/
Args extends (() => readonly [...infer K] | null)
? ((...args: [...K]) => Result<Data>)
SWRKey extends (() => readonly [...infer Args] | null)
? ((...args: [...Args]) => FetcherResponse<Data>)
: /**
* [{ foo: string }, { bar: number } ] | null
*
* [{ foo: string }, { bar: number } ] as const | null
*/
Args extends (readonly [...infer K])
? ((...args: [...K]) => Result<Data>)
SWRKey extends (readonly [...infer Args])
? ((...args: [...Args]) => FetcherResponse<Data>)
: /**
* () => string | null
* () => Record<any, any> | null
*/
Args extends (() => infer T | null)
? (...args: [T]) => Result<Data>
SWRKey extends (() => infer Arg | null)
? (...args: [Arg]) => FetcherResponse<Data>
: /**
* string | null | Record<any,any>
*/
Args extends null
SWRKey extends null
? never
: Args extends (infer T)
? (...args: [T]) => Result<Data>
: SWRKey extends (infer Arg)
? (...args: [Arg]) => FetcherResponse<Data>
: never

// Configuration types that are only used internally, not exposed to the user.
Expand All @@ -41,8 +39,7 @@ export interface InternalConfiguration {
export interface PublicConfiguration<
Data = any,
Error = any,
Args extends Key = Key,
Fn = Fetcher<Data, Args>
SWRKey extends Key = Key
> {
errorRetryInterval: number
errorRetryCount?: number
Expand All @@ -59,29 +56,29 @@ export interface PublicConfiguration<
shouldRetryOnError: boolean
suspense?: boolean
fallbackData?: Data
fetcher?: Fn
fetcher?: Fetcher<Data, SWRKey>
use?: Middleware[]
fallback: { [key: string]: any }

isPaused: () => boolean
onLoadingSlow: (
key: string,
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
config: Readonly<PublicConfiguration<Data, Error, SWRKey>>
) => void
onSuccess: (
data: Data,
key: string,
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
config: Readonly<PublicConfiguration<Data, Error, SWRKey>>
) => void
onError: (
err: Error,
key: string,
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>
config: Readonly<PublicConfiguration<Data, Error, SWRKey>>
) => void
onErrorRetry: (
err: Error,
key: string,
config: Readonly<PublicConfiguration<Data, Error, Args, Fn>>,
config: Readonly<PublicConfiguration<Data, Error, SWRKey>>,
revalidate: Revalidator,
revalidateOpts: Required<RevalidatorOptions>
) => void
Expand All @@ -94,55 +91,54 @@ export interface PublicConfiguration<

export type FullConfiguration = InternalConfiguration & PublicConfiguration

export type ConfigOptions = {
export type ProviderConfiguration = {
initFocus: (callback: () => void) => (() => void) | void
initReconnect: (callback: () => void) => (() => void) | void
}

export interface SWRHook {
<Data = any, Error = any, Args extends Key = Key>(args: Args): SWRResponse<
<Data = any, Error = any, SWRKey extends Key = Key>(key: SWRKey): SWRResponse<
Data,
Error
>
<Data = any, Error = any, Args extends Key = Key>(
args: Args,
fn: Fetcher<Data, Args> | null
<Data = any, Error = any, SWRKey extends Key = Key>(
key: SWRKey,
fetcher: Fetcher<Data, SWRKey> | null
): SWRResponse<Data, Error>
<Data = any, Error = any, Args extends Key = Key>(
args: Args,
config: SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>> | undefined
<Data = any, Error = any, SWRKey extends Key = Key>(
key: SWRKey,
config: SWRConfiguration<Data, Error, SWRKey> | 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>>
<Data = any, Error = any, SWRKey extends Key = Key>(
key: SWRKey,
fetcher: Fetcher<Data, SWRKey>,
config: SWRConfiguration<Data, Error, SWRKey> | undefined
): SWRResponse<Data, Error>
<Data = any, Error = any, Args extends Key = Key>(
<Data = any, Error = any, SWRKey extends Key = Key>(
...args:
| [Args]
| [Args, Fetcher<Data, Args> | null]
| [
Args,
SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>> | undefined
]
| [SWRKey]
| [SWRKey, Fetcher<Data, SWRKey> | null]
| [SWRKey, SWRConfiguration<Data, Error, SWRKey> | undefined]
| [
Args,
SWRKey,
Fetcher<Data, Key> | null,
SWRConfiguration<Data, Error, Args, Fetcher<Data, Args>>
SWRConfiguration<Data, Error, SWRKey> | undefined
]
): SWRResponse<Data, Error>
}

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

export type Middleware = (useSWRNext: SWRHook) => SWRHookWithMiddleware
export type TupleKey = [any, ...unknown[]] | readonly [any, ...unknown[]]
export type ValueKey = string | null | TupleKey | Record<any, any>
export type Key = ValueKey | (() => ValueKey)
type ArgumentsTuple = [any, ...unknown[]] | readonly [any, ...unknown[]]
shuding marked this conversation as resolved.
Show resolved Hide resolved
export type Arguments = string | null | ArgumentsTuple | Record<any, any>
export type Key = Arguments | (() => Arguments)

export type MutatorCallback<Data = any> = (
currentValue?: Data
Expand Down Expand Up @@ -195,9 +191,8 @@ export type KeyedMutator<Data> = (
export type SWRConfiguration<
Data = any,
Error = any,
Args extends Key = Key,
Fn = Fetcher<any, Args>
> = Partial<PublicConfiguration<Data, Error, Args, Fn>>
SWRKey extends Key = Key
> = Partial<PublicConfiguration<Data, Error, SWRKey>>

export interface SWRResponse<Data, Error> {
data?: Data
Expand All @@ -206,7 +201,7 @@ export interface SWRResponse<Data, Error> {
isValidating: boolean
}

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

Expand Down
4 changes: 2 additions & 2 deletions src/utils/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
Cache,
ScopedMutator,
RevalidateCallback,
ConfigOptions
ProviderConfiguration
} from '../types'

const revalidateAllKeys = (
Expand All @@ -24,7 +24,7 @@ const revalidateAllKeys = (

export const initCache = <Data = any>(
provider: Cache<Data>,
options?: Partial<ConfigOptions>
options?: Partial<ProviderConfiguration>
): [Cache<Data>, ScopedMutator<Data>, () => void] | undefined => {
// The global state for a specific provider will be used to deduplicate
// requests and store listeners. As well as a mutate function that bound to
Expand Down
4 changes: 2 additions & 2 deletions src/utils/config-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { useIsomorphicLayoutEffect } from './env'
import {
SWRConfiguration,
FullConfiguration,
ConfigOptions,
ProviderConfiguration,
Cache
} from '../types'

export const SWRConfigContext = createContext<Partial<FullConfiguration>>({})

const SWRConfig: FC<{
value?: SWRConfiguration &
Partial<ConfigOptions> & {
Partial<ProviderConfiguration> & {
provider?: (cache: Readonly<Cache>) => Cache
}
}> = ({ children, value }) => {
Expand Down
4 changes: 2 additions & 2 deletions src/utils/web-preset.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConfigOptions } from '../types'
import { ProviderConfiguration } from '../types'
import { isUndefined, noop, hasWindow, hasDocument } from './helper'

/**
Expand Down Expand Up @@ -62,7 +62,7 @@ export const preset = {
isVisible
} as const

export const defaultConfigOptions: ConfigOptions = {
export const defaultConfigOptions: ProviderConfiguration = {
initFocus,
initReconnect
}