diff --git a/infinite/types.ts b/infinite/types.ts index e77c75b22..f4cc48b8c 100644 --- a/infinite/types.ts +++ b/infinite/types.ts @@ -1,4 +1,4 @@ -import { SWRConfiguration, SWRResponse, Arguments } from 'swr' +import { SWRConfiguration, SWRResponse, Arguments, BareFetcher } from 'swr' type FetcherResponse = Data | Promise @@ -9,6 +9,8 @@ export type InfiniteFetcher< ? ((...args: [...K]) => FetcherResponse) : Args extends null ? never + : Args extends false + ? never : Args extends (infer T) ? (...args: [T]) => FetcherResponse : never @@ -57,4 +59,20 @@ export interface SWRInfiniteHook { | SWRInfiniteConfiguration | undefined ): SWRInfiniteResponse + ( + getKey: InfiniteKeyLoader + ): SWRInfiniteResponse + ( + getKey: InfiniteKeyLoader, + fetcher: BareFetcher | null + ): SWRInfiniteResponse + ( + getKey: InfiniteKeyLoader, + config: SWRInfiniteConfiguration | undefined + ): SWRInfiniteResponse + ( + getKey: InfiniteKeyLoader, + fetcher: BareFetcher | null, + config: SWRInfiniteConfiguration | undefined + ): SWRInfiniteResponse } diff --git a/src/index.ts b/src/index.ts index 47b5e9831..f46a99e97 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,6 +18,7 @@ export { SWRResponse, Cache, SWRHook, + BareFetcher, Fetcher, MutatorCallback, Middleware, diff --git a/src/types.ts b/src/types.ts index 71bd09eb3..972063e9a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,34 +1,23 @@ import * as revalidateEvents from './constants/revalidate-events' export type FetcherResponse = Data | Promise - -export type Fetcher = - /** - * () => [{ foo: string }, { bar: number }] | null | undefined | false - * () => ( [{ foo: string }, { bar: number } ] as const | null | undefined | false ) - */ - SWRKey extends (() => readonly [...infer Args] | null | undefined | false) - ? ((...args: [...Args]) => FetcherResponse) - : /** - * [{ foo: string }, { bar: number }] - * [{ foo: string }, { bar: number }] as const - */ - SWRKey extends (readonly [...infer Args]) - ? ((...args: [...Args]) => FetcherResponse) - : /** - * () => string | null | undefined | false - * () => Record | null | undefined | false - */ - SWRKey extends (() => infer Arg | null | undefined | false) - ? (...args: [Arg]) => FetcherResponse - : /** - * string | Record | null | undefined | false - */ - SWRKey extends null | undefined | false - ? never - : SWRKey extends (infer Arg) - ? (...args: [Arg]) => FetcherResponse - : never +export type BareFetcher = ( + ...args: any[] +) => FetcherResponse +export type Fetcher< + Data = unknown, + SWRKey extends Key = Key +> = SWRKey extends (() => readonly [...infer Args] | null | undefined | false) + ? ((...args: [...Args]) => FetcherResponse) + : SWRKey extends (readonly [...infer Args]) + ? ((...args: [...Args]) => FetcherResponse) + : SWRKey extends (() => infer Arg | null | undefined | false) + ? (...args: [Arg]) => FetcherResponse + : SWRKey extends null | undefined | false + ? never + : SWRKey extends (infer Arg) + ? (...args: [Arg]) => FetcherResponse + : never // Configuration types that are only used internally, not exposed to the user. export interface InternalConfiguration { @@ -126,6 +115,31 @@ export interface SWRHook { SWRConfiguration | undefined ] ): SWRResponse + (key: Key): SWRResponse + ( + key: Key, + fetcher: BareFetcher | null + ): SWRResponse + ( + key: Key, + config: SWRConfiguration | undefined + ): SWRResponse + ( + key: Key, + fetcher: BareFetcher, + config: SWRConfiguration | undefined + ): SWRResponse + ( + ...args: + | [Key] + | [Key, BareFetcher | null] + | [Key, SWRConfiguration | undefined] + | [ + Key, + BareFetcher | null, + SWRConfiguration | undefined + ] + ): SWRResponse } // Middlewares guarantee that a SWRHook receives a key, fetcher, and config as the argument diff --git a/test/type/fetcher.ts b/test/type/fetcher.ts index 4183809a7..38f29eb46 100644 --- a/test/type/fetcher.ts +++ b/test/type/fetcher.ts @@ -6,6 +6,11 @@ const expectType: ExpectType = () => {} const truthy: () => boolean = () => true +export function useDataErrorGeneric() { + useSWR<{ id: number }>('/api/', () => ({ id: 123 })) + useSWR('/api/', (key: string) => key) +} + export function useString() { useSWR('/api/user', key => { expectType(key) @@ -15,6 +20,11 @@ export function useString() { expectType(key) return key }) + + useSWR(truthy() ? '/api/user' : false, key => { + expectType(key) + return key + }) } export function useRecord() { @@ -26,6 +36,10 @@ export function useRecord() { expectType<{ a: string; b: { c: string; d: number } }>(key) return key }) + useSWR(truthy() ? { a: '1', b: { c: '3', d: 2 } } : false, key => { + expectType<{ a: string; b: { c: string; d: number } }>(key) + return key + }) } export function useTuple() { @@ -40,6 +54,13 @@ export function useTuple() { return keys } ) + useSWR( + truthy() ? [{ a: '1', b: { c: '3' } }, [1231, '888']] : false, + (...keys) => { + expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys) + return keys + } + ) } export function useReadonlyTuple() { @@ -74,6 +95,23 @@ export function useReadonlyTuple() { return keys } ) + useSWR( + truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : false, + (...keys) => { + expectType< + [ + { + readonly a: '1' + readonly b: { + readonly c: '3' + } + }, + readonly [1231, '888'] + ] + >(keys) + return keys + } + ) } export function useReturnString() { @@ -92,6 +130,14 @@ export function useReturnString() { } ) + useSWR( + () => (truthy() ? '/api/user' : false), + key => { + expectType(key) + return key + } + ) + useSWRInfinite( (index, previousPageData: string) => { return `${index}${previousPageData}` @@ -111,6 +157,15 @@ export function useReturnString() { return key } ) + useSWRInfinite( + (index, previousPageData: string) => { + return truthy() ? `${index}${previousPageData}` : false + }, + key => { + expectType(key) + return key + } + ) } export function useReturnRecord() { @@ -129,6 +184,14 @@ export function useReturnRecord() { } ) + useSWR( + () => (truthy() ? { a: '1', b: { c: '3', d: 2 } } : false), + key => { + expectType<{ a: string; b: { c: string; d: number } }>(key) + return key + } + ) + useSWRInfinite( index => ({ index, @@ -153,6 +216,20 @@ export function useReturnRecord() { return [key] } ) + + useSWRInfinite( + index => + truthy() + ? { + index, + endPoint: '/api' + } + : false, + key => { + expectType<{ index: number; endPoint: string }>(key) + return [key] + } + ) } export function useReturnTuple() { @@ -171,6 +248,14 @@ export function useReturnTuple() { } ) + useSWR( + () => (truthy() ? [{ a: '1', b: { c: '3' } }, [1231, '888']] : false), + (...keys) => { + expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys) + return keys + } + ) + useSWRInfinite( index => [{ a: '1', b: { c: '3', d: index } }, [1231, '888']], (...keys) => { @@ -187,6 +272,15 @@ export function useReturnTuple() { return keys[1] } ) + + useSWRInfinite( + index => + truthy() ? [{ a: '1', b: { c: '3', d: index } }, [1231, '888']] : false, + (...keys) => { + expectType<[{ a: string; b: { c: string } }, (string | number)[]]>(keys) + return keys[1] + } + ) } export function useReturnReadonlyTuple() { @@ -226,6 +320,25 @@ export function useReturnReadonlyTuple() { } ) + useSWR( + () => + truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : false, + (...keys) => { + expectType< + [ + { + readonly a: '1' + readonly b: { + readonly c: '3' + } + }, + readonly [1231, '888'] + ] + >(keys) + return keys + } + ) + useSWRInfinite( () => [{ a: '1', b: { c: '3' } }, [1231, '888']] as const, (...keys) => { @@ -261,4 +374,23 @@ export function useReturnReadonlyTuple() { return keys[1] } ) + + useSWRInfinite( + () => + truthy() ? ([{ a: '1', b: { c: '3' } }, [1231, '888']] as const) : false, + (...keys) => { + expectType< + [ + { + readonly a: '1' + readonly b: { + readonly c: '3' + } + }, + readonly [1231, '888'] + ] + >(keys) + return keys[1] + } + ) }