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

breaking: Change the fetcher argument to be consistent with the passed key #1864

Merged
merged 4 commits into from Apr 3, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions infinite/index.ts
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
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
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
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
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
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