From 70262f7543f419fc96dec9219051cf928fc5f9a2 Mon Sep 17 00:00:00 2001 From: Yixuan Xu Date: Tue, 16 Nov 2021 19:57:15 +0800 Subject: [PATCH 1/7] test: add test for #1586 Author: YixuanXu Date: Tue Nov 16 19:57:15 2021 +0800 --- test/type/fetcher.ts | 127 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/test/type/fetcher.ts b/test/type/fetcher.ts index 4183809a7..d7af05da8 100644 --- a/test/type/fetcher.ts +++ b/test/type/fetcher.ts @@ -15,6 +15,11 @@ export function useString() { expectType(key) return key }) + + useSWR(truthy() ? '/api/user' : false, key => { + expectType(key) + return key + }) } export function useRecord() { @@ -26,6 +31,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 +49,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 +90,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 +125,14 @@ export function useReturnString() { } ) + useSWR( + () => (truthy() ? '/api/user' : false), + key => { + expectType(key) + return key + } + ) + useSWRInfinite( (index, previousPageData: string) => { return `${index}${previousPageData}` @@ -111,6 +152,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 +179,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 +211,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 +243,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 +267,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 +315,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 +369,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] + } + ) } From 076dad8a300ba3c9d472ef454064e297e4b5e095 Mon Sep 17 00:00:00 2001 From: Yixuan Xu Date: Tue, 16 Nov 2021 19:58:38 +0800 Subject: [PATCH 2/7] fix: allow user to use generics Author: YixuanXu Date: Tue Nov 16 19:58:38 2021 +0800 --- infinite/types.ts | 22 ++++++++++++++++++++ src/types.ts | 53 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/infinite/types.ts b/infinite/types.ts index e77c75b22..7fa873f22 100644 --- a/infinite/types.ts +++ b/infinite/types.ts @@ -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,24 @@ export interface SWRInfiniteHook { | SWRInfiniteConfiguration | undefined ): SWRInfiniteResponse + /** + * allow user to use generics like this + * useSWR<{foo: string}>(key, fn) + */ + ( + getKey: InfiniteKeyLoader + ): SWRInfiniteResponse + ( + getKey: InfiniteKeyLoader, + fetcher: InfiniteFetcher | null + ): SWRInfiniteResponse + ( + getKey: InfiniteKeyLoader, + config: SWRInfiniteConfiguration | undefined + ): SWRInfiniteResponse + ( + getKey: InfiniteKeyLoader, + fetcher: InfiniteFetcher | null, + config: SWRInfiniteConfiguration | undefined + ): SWRInfiniteResponse } diff --git a/src/types.ts b/src/types.ts index 71bd09eb3..47ec18486 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,22 +9,22 @@ export type Fetcher = */ 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]) + /** + * [{ 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) + /** + * () => 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 + /** + * string | Record | null | undefined | false + */ + : SWRKey extends null | undefined | false ? never : SWRKey extends (infer Arg) ? (...args: [Arg]) => FetcherResponse @@ -126,6 +126,31 @@ export interface SWRHook { SWRConfiguration | undefined ] ): SWRResponse + /** + * allow people to use generics like this + * useSWR<{foo: string}>(key, fn) + */ + (key: Key): SWRResponse + ( + key: Key, + fetcher: Fetcher | null + ): SWRResponse + ( + key: Key, + config: SWRConfiguration | undefined + ): SWRResponse + ( + key: Key, + fetcher: Fetcher, + config: SWRConfiguration | undefined + ): SWRResponse + ( + ...args: + | [Key] + | [Key, Fetcher | null] + | [Key, SWRConfiguration | undefined] + | [Key, Fetcher | null, SWRConfiguration | undefined] + ): SWRResponse } // Middlewares guarantee that a SWRHook receives a key, fetcher, and config as the argument From 1718ac54af0e60123cbf434ab067068b73bb684a Mon Sep 17 00:00:00 2001 From: YixuanXu Date: Sat, 20 Nov 2021 00:46:34 +0800 Subject: [PATCH 3/7] chore: remove comments --- infinite/types.ts | 4 ---- src/types.ts | 32 ++++++++++++++------------------ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/infinite/types.ts b/infinite/types.ts index 7fa873f22..fcca89d86 100644 --- a/infinite/types.ts +++ b/infinite/types.ts @@ -59,10 +59,6 @@ export interface SWRInfiniteHook { | SWRInfiniteConfiguration | undefined ): SWRInfiniteResponse - /** - * allow user to use generics like this - * useSWR<{foo: string}>(key, fn) - */ ( getKey: InfiniteKeyLoader ): SWRInfiniteResponse diff --git a/src/types.ts b/src/types.ts index 47ec18486..907d690b5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,22 +9,22 @@ export type Fetcher = */ 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]) + : /** + * [{ 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) + : /** + * () => 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 + : /** + * string | Record | null | undefined | false + */ + SWRKey extends null | undefined | false ? never : SWRKey extends (infer Arg) ? (...args: [Arg]) => FetcherResponse @@ -126,10 +126,6 @@ export interface SWRHook { SWRConfiguration | undefined ] ): SWRResponse - /** - * allow people to use generics like this - * useSWR<{foo: string}>(key, fn) - */ (key: Key): SWRResponse ( key: Key, From 03c76507bf26826b50708e495203e90160c6b88a Mon Sep 17 00:00:00 2001 From: YixuanXu Date: Sat, 20 Nov 2021 01:08:08 +0800 Subject: [PATCH 4/7] fix: allow fallback to origin fetcher --- infinite/types.ts | 6 +++--- src/index.ts | 1 + src/types.ts | 44 +++++++++++++++++++++++++------------------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/infinite/types.ts b/infinite/types.ts index fcca89d86..dec019410 100644 --- a/infinite/types.ts +++ b/infinite/types.ts @@ -1,4 +1,4 @@ -import { SWRConfiguration, SWRResponse, Arguments } from 'swr' +import { SWRConfiguration, SWRResponse, Arguments, OriginFetcher } from 'swr' type FetcherResponse = Data | Promise @@ -64,7 +64,7 @@ export interface SWRInfiniteHook { ): SWRInfiniteResponse ( getKey: InfiniteKeyLoader, - fetcher: InfiniteFetcher | null + fetcher: OriginFetcher | null ): SWRInfiniteResponse ( getKey: InfiniteKeyLoader, @@ -72,7 +72,7 @@ export interface SWRInfiniteHook { ): SWRInfiniteResponse ( getKey: InfiniteKeyLoader, - fetcher: InfiniteFetcher | null, + fetcher: OriginFetcher | null, config: SWRInfiniteConfiguration | undefined ): SWRInfiniteResponse } diff --git a/src/index.ts b/src/index.ts index 47b5e9831..dd229b687 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,6 +18,7 @@ export { SWRResponse, Cache, SWRHook, + OriginFetcher, Fetcher, MutatorCallback, Middleware, diff --git a/src/types.ts b/src/types.ts index 907d690b5..b889f60ef 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,9 @@ import * as revalidateEvents from './constants/revalidate-events' export type FetcherResponse = Data | Promise - +export type OriginFetcher = ( + ...args: any[] +) => FetcherResponse export type Fetcher = /** * () => [{ foo: string }, { bar: number }] | null | undefined | false @@ -9,22 +11,22 @@ export type Fetcher = */ 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]) + /** + * [{ 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) + /** + * () => 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 + /** + * string | Record | null | undefined | false + */ + : SWRKey extends null | undefined | false ? never : SWRKey extends (infer Arg) ? (...args: [Arg]) => FetcherResponse @@ -129,7 +131,7 @@ export interface SWRHook { (key: Key): SWRResponse ( key: Key, - fetcher: Fetcher | null + fetcher: OriginFetcher | null ): SWRResponse ( key: Key, @@ -137,15 +139,19 @@ export interface SWRHook { ): SWRResponse ( key: Key, - fetcher: Fetcher, + fetcher: OriginFetcher, config: SWRConfiguration | undefined ): SWRResponse ( ...args: | [Key] - | [Key, Fetcher | null] + | [Key, OriginFetcher | null] | [Key, SWRConfiguration | undefined] - | [Key, Fetcher | null, SWRConfiguration | undefined] + | [ + Key, + OriginFetcher | null, + SWRConfiguration | undefined + ] ): SWRResponse } From ede734b9b802699cbee1ad2186a800219a2ff45b Mon Sep 17 00:00:00 2001 From: YixuanXu Date: Sat, 20 Nov 2021 01:12:40 +0800 Subject: [PATCH 5/7] chore: remove comment --- src/types.ts | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/src/types.ts b/src/types.ts index b889f60ef..d7cbfb00c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,33 +4,20 @@ export type FetcherResponse = Data | Promise export type OriginFetcher = ( ...args: any[] ) => FetcherResponse -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 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 { From 62f5a5c4baf08a10a75b6a698dad48579868ec29 Mon Sep 17 00:00:00 2001 From: YixuanXu Date: Mon, 22 Nov 2021 23:51:11 +0800 Subject: [PATCH 6/7] chore: rename to barefetcher --- infinite/types.ts | 6 +++--- src/index.ts | 2 +- src/types.ts | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/infinite/types.ts b/infinite/types.ts index dec019410..f4cc48b8c 100644 --- a/infinite/types.ts +++ b/infinite/types.ts @@ -1,4 +1,4 @@ -import { SWRConfiguration, SWRResponse, Arguments, OriginFetcher } from 'swr' +import { SWRConfiguration, SWRResponse, Arguments, BareFetcher } from 'swr' type FetcherResponse = Data | Promise @@ -64,7 +64,7 @@ export interface SWRInfiniteHook { ): SWRInfiniteResponse ( getKey: InfiniteKeyLoader, - fetcher: OriginFetcher | null + fetcher: BareFetcher | null ): SWRInfiniteResponse ( getKey: InfiniteKeyLoader, @@ -72,7 +72,7 @@ export interface SWRInfiniteHook { ): SWRInfiniteResponse ( getKey: InfiniteKeyLoader, - fetcher: OriginFetcher | null, + fetcher: BareFetcher | null, config: SWRInfiniteConfiguration | undefined ): SWRInfiniteResponse } diff --git a/src/index.ts b/src/index.ts index dd229b687..f46a99e97 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,7 +18,7 @@ export { SWRResponse, Cache, SWRHook, - OriginFetcher, + BareFetcher, Fetcher, MutatorCallback, Middleware, diff --git a/src/types.ts b/src/types.ts index d7cbfb00c..972063e9a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,7 @@ import * as revalidateEvents from './constants/revalidate-events' export type FetcherResponse = Data | Promise -export type OriginFetcher = ( +export type BareFetcher = ( ...args: any[] ) => FetcherResponse export type Fetcher< @@ -118,7 +118,7 @@ export interface SWRHook { (key: Key): SWRResponse ( key: Key, - fetcher: OriginFetcher | null + fetcher: BareFetcher | null ): SWRResponse ( key: Key, @@ -126,17 +126,17 @@ export interface SWRHook { ): SWRResponse ( key: Key, - fetcher: OriginFetcher, + fetcher: BareFetcher, config: SWRConfiguration | undefined ): SWRResponse ( ...args: | [Key] - | [Key, OriginFetcher | null] + | [Key, BareFetcher | null] | [Key, SWRConfiguration | undefined] | [ Key, - OriginFetcher | null, + BareFetcher | null, SWRConfiguration | undefined ] ): SWRResponse From 33dd46acbfab0b5c33e3c19cb26a85d349bf6202 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Tue, 23 Nov 2021 13:13:32 +0100 Subject: [PATCH 7/7] add test --- test/type/fetcher.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/type/fetcher.ts b/test/type/fetcher.ts index d7af05da8..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)