Skip to content

Commit

Permalink
breaking: Change the fetcher argument to be consistent with the passe…
Browse files Browse the repository at this point in the history
…d key (#1864)

* change the fetcher argument to be consistent with the key

* fix test cases

* fix type checks
  • Loading branch information
shuding authored Apr 3, 2022
1 parent e734efe commit 12cc327
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 88 deletions.
4 changes: 2 additions & 2 deletions infinite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export const infinite = (<Data, Error>(useSWRNext: SWRHook) =>

let previousPageData = null
for (let i = 0; i < pageSize; ++i) {
const [pageKey, pageArgs] = serialize(getKey(i, previousPageData))
const [pageKey, pageArg] = serialize(getKey(i, previousPageData))

if (!pageKey) {
// `pageKey` is falsy, stop fetching new pages.
Expand Down Expand Up @@ -148,7 +148,7 @@ export const infinite = (<Data, Error>(useSWRNext: SWRHook) =>
!config.compare(originalData[i], pageData))

if (fn && shouldFetchPage) {
pageData = await fn(...pageArgs)
pageData = await fn(pageArg)
cache.set(pageKey, pageData)
}

Expand Down
10 changes: 3 additions & 7 deletions infinite/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ export type SWRInfiniteFetcher<
Data = any,
KeyLoader extends SWRInfiniteKeyLoader = SWRInfiniteKeyLoader
> = KeyLoader extends (...args: any[]) => any
? ReturnType<KeyLoader> extends
| readonly [...infer K]
| null
| false
| undefined
? (...args: [...K]) => FetcherResponse<Data>
? ReturnType<KeyLoader> extends readonly [...infer T]
? (args: T) => FetcherResponse<Data>
: ReturnType<KeyLoader> extends infer T | null | false | undefined
? (...args: [T]) => FetcherResponse<Data>
? (args: T) => FetcherResponse<Data>
: never
: never

Expand Down
10 changes: 5 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ export type BareFetcher<Data = unknown> = (
export type Fetcher<
Data = unknown,
SWRKey extends Key = Key
> = SWRKey extends () => readonly [...infer Args] | null | undefined | false
? (...args: [...Args]) => FetcherResponse<Data>
> = SWRKey extends () => readonly [...infer Args]
? (args: Args) => FetcherResponse<Data>
: SWRKey extends readonly [...infer Args]
? (...args: [...Args]) => FetcherResponse<Data>
? (args: Args) => FetcherResponse<Data>
: SWRKey extends () => infer Arg | null | undefined | false
? (...args: [Arg]) => FetcherResponse<Data>
? (args: Arg) => FetcherResponse<Data>
: SWRKey extends null | undefined | false
? never
: SWRKey extends infer Arg
? (...args: [Arg]) => FetcherResponse<Data>
? (args: Arg) => FetcherResponse<Data>
: never

// Configuration types that are only used internally, not exposed to the user.
Expand Down
24 changes: 20 additions & 4 deletions src/use-swr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ import {

const WITH_DEDUPE = { dedupe: true }

type DefinitelyTruthy<T> = false extends T
? never
: 0 extends T
? never
: '' extends T
? never
: null extends T
? never
: undefined extends T
? never
: T

export const useSWRHandler = <Data = any, Error = any>(
_key: Key,
fetcher: Fetcher<Data> | null,
Expand All @@ -55,9 +67,9 @@ export const useSWRHandler = <Data = any, Error = any>(
// `key` is the identifier of the SWR `data` state, `keyInfo` holds extra
// states such as `error` and `isValidating` inside,
// all of them are derived from `_key`.
// `fnArgs` is an array of arguments parsed from the key, which will be passed
// `fnArg` is the argument/arguments parsed from the key, which will be passed
// to the fetcher.
const [key, fnArgs, keyInfo] = serialize(_key)
const [key, fnArg, keyInfo] = serialize(_key)

// If it's the initial render of this hook.
const initialMountedRef = useRef(false)
Expand Down Expand Up @@ -205,7 +217,11 @@ export const useSWRHandler = <Data = any, Error = any>(
}

// Start the request and save the timestamp.
FETCH[key] = [currentFetcher(...fnArgs), getTimestamp()]
// Key must be truthly if entering here.
FETCH[key] = [
currentFetcher(fnArg as DefinitelyTruthy<Key>),
getTimestamp()
]
}

// Wait until the ongoing request is done. Deduplication is also
Expand Down Expand Up @@ -342,7 +358,7 @@ export const useSWRHandler = <Data = any, Error = any>(

return true
},
// `setState` is immutable, and `eventsCallback`, `fnArgs`, `keyInfo`,
// `setState` is immutable, and `eventsCallback`, `fnArg`, `keyInfo`,
// and `keyValidating` are depending on `key`, so we can exclude them from
// the deps array.
//
Expand Down
6 changes: 4 additions & 2 deletions 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] => {
export const serialize = (key: Key): [string, Key, string] => {
if (isFunction(key)) {
try {
key = key()
Expand All @@ -13,7 +13,9 @@ export const serialize = (key: Key): [string, any[], string] => {
}
}

const args = [].concat(key as any)
// Use the original key as the argument of fether. This can be a stirng or an
// array of values.
const args = key

// If key is not falsy, or not an empty array, hash it.
key =
Expand Down
55 changes: 26 additions & 29 deletions test/type/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,28 +58,25 @@ export function useRecord() {
}

export function useTuple() {
useSWR([{ a: '1', b: { c: '3' } }, [1231, '888']], (...keys) => {
useSWR([{ a: '1', b: { c: '3' } }, [1231, '888']], keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys
})
useSWR(truthy() ? [{ a: '1', b: { c: '3' } }, [1231, '888']] : null, keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys
})
useSWR(
truthy() ? [{ a: '1', b: { c: '3' } }, [1231, '888']] : null,
(...keys) => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys
}
)
useSWR(
truthy() ? [{ a: '1', b: { c: '3' } }, [1231, '888']] : false,
(...keys) => {
keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys
}
)
}

export function useReadonlyTuple() {
useSWR([{ a: '1', b: { c: '3' } }, [1231, '888']] as const, (...keys) => {
useSWR([{ a: '1', b: { c: '3' } }, [1231, '888']] as const, keys => {
expectType<
[
{
Expand All @@ -95,7 +92,7 @@ export function useReadonlyTuple() {
})
useSWR(
truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : null,
(...keys) => {
keys => {
expectType<
[
{
Expand All @@ -112,7 +109,7 @@ export function useReadonlyTuple() {
)
useSWR(
truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : false,
(...keys) => {
keys => {
expectType<
[
{
Expand Down Expand Up @@ -250,30 +247,30 @@ export function useReturnRecord() {
export function useReturnTuple() {
useSWR(
() => [{ a: '1', b: { c: '3' } }, [1231, '888']],
(...keys) => {
keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys
}
)
useSWR(
() => (truthy() ? [{ a: '1', b: { c: '3' } }, [1231, '888']] : null),
(...keys) => {
keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys
}
)

useSWR(
() => (truthy() ? [{ a: '1', b: { c: '3' } }, [1231, '888']] : false),
(...keys) => {
keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys
}
)

useSWRInfinite(
index => [{ a: '1', b: { c: '3', d: index } }, [1231, '888']],
(...keys) => {
keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys[1]
}
Expand All @@ -282,7 +279,7 @@ export function useReturnTuple() {
useSWRInfinite(
index =>
truthy() ? [{ a: '1', b: { c: '3', d: index } }, [1231, '888']] : null,
(...keys) => {
keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys[1]
}
Expand All @@ -291,7 +288,7 @@ export function useReturnTuple() {
useSWRInfinite(
index =>
truthy() ? [{ a: '1', b: { c: '3', d: index } }, [1231, '888']] : false,
(...keys) => {
keys => {
expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys)
return keys[1]
}
Expand All @@ -301,7 +298,7 @@ export function useReturnTuple() {
export function useReturnReadonlyTuple() {
useSWR(
() => [{ a: '1', b: { c: '3' } }, [1231, '888']] as const,
(...keys) => {
keys => {
expectType<
[
{
Expand All @@ -319,9 +316,9 @@ export function useReturnReadonlyTuple() {
useSWR(
() =>
truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : null,
(...keys) => {
keys => {
expectType<
[
readonly [
{
readonly a: '1'
readonly b: {
Expand All @@ -338,9 +335,9 @@ export function useReturnReadonlyTuple() {
useSWR(
() =>
truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : false,
(...keys) => {
keys => {
expectType<
[
readonly [
{
readonly a: '1'
readonly b: {
Expand All @@ -356,9 +353,9 @@ export function useReturnReadonlyTuple() {

useSWRInfinite(
() => [{ a: '1', b: { c: '3' } }, [1231, '888']] as const,
(...keys) => {
keys => {
expectType<
[
readonly [
{
readonly a: '1'
readonly b: {
Expand All @@ -374,9 +371,9 @@ export function useReturnReadonlyTuple() {
useSWRInfinite(
() =>
truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : null,
(...keys) => {
keys => {
expectType<
[
readonly [
{
readonly a: '1'
readonly b: {
Expand All @@ -393,9 +390,9 @@ export function useReturnReadonlyTuple() {
useSWRInfinite(
() =>
truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : false,
(...keys) => {
keys => {
expectType<
[
readonly [
{
readonly a: '1'
readonly b: {
Expand Down
Loading

0 comments on commit 12cc327

Please sign in to comment.