From 75274571747a65a8706da3f8f63df79da912dc54 Mon Sep 17 00:00:00 2001 From: Kevin Sullivan Date: Sun, 28 Jun 2020 17:01:27 -0700 Subject: [PATCH] fix(types): v2 (#626) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enable types, update simpleQuery * update MutationState * stricter query type Co-authored-by: Michaël De Boey * verify imports * verify import 2 * update fetchMore * move ready condition to enabled * update MutateOptions * update config * fix QueryResulltBase * remove queryKey function * remove duplicate type * update prefetch * functions are not valid queryKeys * add option to queryFn, formatting * Add dtslinting to ci test * remove deprecated variables * add types to formatting * add resetErrorBoundaries Co-authored-by: Michaël De Boey --- package.json | 10 +- types/index.d.ts | 271 +++++++++++++++++---------------------------- types/test.ts | 276 +++++++++++++++++++++++++++++----------------- types/tslint.json | 3 +- yarn.lock | 23 ++++ 5 files changed, 304 insertions(+), 279 deletions(-) diff --git a/package.json b/package.json index 3d3fd056c4..e2842a5d0f 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,13 @@ "repository": "tannerlinsley/react-query", "homepage": "https://github.com/tannerlinsley/react-query#readme", "main": "index.js", - "_temporarily_disabled_types": "types/index.d.ts", + "types": "types/index.d.ts", "module": "dist/react-query.mjs", "sideEffects": false, "scripts": { "test": "is-ci \"test:ci\" \"test:dev\"", "test:dev": "jest --watch", - "test:ci": "jest", + "test:ci": "jest && yarn dtslint", "test:coverage": "yarn test:ci; open coverage/lcov-report/index.html", "build": "NODE_ENV=production rollup -c", "now-build": "yarn && cd www && yarn && yarn build", @@ -22,7 +22,7 @@ "prepublishOnly": "yarn test:ci && yarn formatReadme", "release": "yarn publish", "releaseNext": "yarn publish --tag next", - "format": "prettier {.,src,src/**,example/src,example/src/**}/*.{md,js,jsx,tsx,json} --write", + "format": "prettier {.,src,src/**,example/src,example/src/**,types}/*.{md,js,jsx,tsx,json} --write", "formatReadme": "yarn doctoc", "doctoc": "npx doctoc --maxlevel 2 README.md", "jump2header": "npx @strdr4605/jump2header --header 'documentation' --start 'Installation' -e 2 --silent -l 2", @@ -59,6 +59,7 @@ "@rollup/plugin-replace": "^2.3.3", "@svgr/rollup": "^5.4.0", "@testing-library/react": "^10.2.1", + "@types/react": "^16.9.41", "babel-eslint": "^10.1.0", "babel-jest": "^26.0.1", "babel-plugin-transform-async-to-promises": "^0.8.15", @@ -93,6 +94,7 @@ "rollup-plugin-prettier": "^2.1.0", "rollup-plugin-size": "^0.2.2", "rollup-plugin-terser": "^6.1.0", - "rollup-plugin-visualizer": "^4.0.4" + "rollup-plugin-visualizer": "^4.0.4", + "typescript": "^3.9.5" } } diff --git a/types/index.d.ts b/types/index.d.ts index 2c762fbcd0..8d807f7570 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2,79 +2,48 @@ // Jace Hensley // Matteo Frana // Igor Oleinikov -// Minimum TypeScript Version: 3.7 +// Minimum TypeScript Version: 3.9 import * as React from 'react' import * as _ from 'ts-toolbelt' // overloaded useQuery function +export type UseQueryRest = + | [] + | [QueryFunction] + | [QueryFunction, QueryOptions] + | [QueryOptions] + +// Object Syntax export function useQuery({ queryKey, queryFn, config, }: { queryKey: TKey - queryFn: QueryFunction + queryFn?: QueryFunction config?: QueryOptions }): QueryResult -export function useQuery({ +export function useQuery({ queryKey, queryFn, config, }: { - queryKey: - | TSingleKey - | false - | null - | undefined - | (() => TSingleKey | false | null | undefined) - queryFn: QueryFunction + queryKey: TKey + queryFn?: QueryFunction config?: QueryOptions }): QueryResult +// Parameters Syntax export function useQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), - queryFn: QueryFunction, - config?: QueryOptions -): QueryResult - -export function useQuery( - queryKey: - | TSingleKey - | false - | null - | undefined - | (() => TSingleKey | false | null | undefined), - queryFn: QueryFunction, - config?: QueryOptions -): QueryResult - -export function useQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), - queryFn: QueryFunction, - config?: QueryOptions + queryKey: TKey | false | null | undefined, + ...rest: UseQueryRest ): QueryResult export function useQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), - queryFn: QueryFunction, - config?: QueryOptions + queryKey: TKey | false | null | undefined, + ...rest: UseQueryRest ): QueryResult // usePaginatedQuery @@ -87,12 +56,7 @@ export function usePaginatedQuery< queryFn, config, }: { - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined) + queryKey: TKey | false | null | undefined queryFn: QueryFunction config?: QueryOptions }): PaginatedQueryResult @@ -106,12 +70,7 @@ export function usePaginatedQuery< queryFn, config, }: { - queryKey: - | TSingleKey - | false - | null - | undefined - | (() => TSingleKey | false | null | undefined) + queryKey: TSingleKey | false | null | undefined queryFn: QueryFunction config?: QueryOptions }): PaginatedQueryResult @@ -121,23 +80,13 @@ export function usePaginatedQuery< TKey extends AnyQueryKey, TError = Error >( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: TKey | false | null | undefined, queryFn: QueryFunction, config?: QueryOptions ): PaginatedQueryResult export function usePaginatedQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: TKey | false | null | undefined, queryFn: QueryFunction, config?: QueryOptions ): PaginatedQueryResult @@ -147,28 +96,19 @@ export function usePaginatedQuery< TKey extends AnyQueryKey, TError = Error >( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: TKey | false | null | undefined, queryFn: QueryFunction, config?: QueryOptions ): PaginatedQueryResult export function usePaginatedQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: TKey | false | null | undefined, queryFn: QueryFunction, config?: QueryOptions ): PaginatedQueryResult // useInfiniteQuery +export type InfiniteQueryKey = T | false | null | undefined export function useInfiniteQuery< TResult, TKey extends AnyQueryKey, @@ -179,13 +119,8 @@ export function useInfiniteQuery< queryFn, config, }: { - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined) - queryFn: InfiniteQueryFunction + queryKey: InfiniteQueryKey + queryFn?: InfiniteQueryFunction config?: InfiniteQueryOptions }): InfiniteQueryResult @@ -199,13 +134,8 @@ export function useInfiniteQuery< queryFn, config, }: { - queryKey: - | TSingleKey - | false - | null - | undefined - | (() => TSingleKey | false | null | undefined) - queryFn: InfiniteQueryFunction + queryKey: InfiniteQueryKey + queryFn?: InfiniteQueryFunction config?: InfiniteQueryOptions }): InfiniteQueryResult @@ -215,12 +145,7 @@ export function useInfiniteQuery< TMoreVariable, TError = Error >( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: InfiniteQueryKey, queryFn: InfiniteQueryFunction, config?: InfiniteQueryOptions ): InfiniteQueryResult @@ -231,12 +156,7 @@ export function useInfiniteQuery< TMoreVariable, TError = Error >( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: InfiniteQueryKey, queryFn: InfiniteQueryFunction, config?: InfiniteQueryOptions ): InfiniteQueryResult @@ -247,12 +167,7 @@ export function useInfiniteQuery< TMoreVariable, TError = Error >( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: InfiniteQueryKey, queryFn: InfiniteQueryFunction, config?: InfiniteQueryOptions ): InfiniteQueryResult @@ -263,12 +178,7 @@ export function useInfiniteQuery< TMoreVariable, TError = Error >( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: InfiniteQueryKey, queryFn: InfiniteQueryFunction, config?: InfiniteQueryOptions ): InfiniteQueryResult @@ -292,7 +202,7 @@ export type QueryKeyPart = export type AnyQueryKey = readonly [DefinedQueryKeyPart, ...QueryKeyPart[]] // this forces the key to be inferred as a tuple export type QueryFunction = ( - ...key: TKey + ...key: Readonly ) => Promise export type InfiniteQueryFunction< @@ -309,10 +219,9 @@ export interface BaseSharedOptions { export interface BaseQueryOptions { /** - * Set this to `true` to disable automatic refetching when the query mounts or changes query keys. + * Set this to `false` to disable automatic refetching when the query mounts or changes query keys. * To refetch the query, use the `refetch` method returned from the `useQuery` instance. */ - manual?: boolean enabled?: boolean /** * If `false`, failed queries will not retry by default. @@ -330,7 +239,7 @@ export interface BaseQueryOptions { refetchOnMount?: boolean onSuccess?: (data: any) => void onError?: (err: TError) => void - onSettled?: (data: any | undefined, error: TError | null) => void + onSettled?: (data: any, error: TError | null) => void isDataEqual?: (oldData: unknown, newData: unknown) => boolean useErrorBoundary?: boolean } @@ -344,8 +253,7 @@ export interface QueryOptions initialStale?: boolean | (() => boolean | undefined) } -export interface PrefetchQueryOptions - extends QueryOptions { +export interface PrefetchQueryOptions { force?: boolean throwOnError?: boolean } @@ -374,12 +282,28 @@ export interface QueryResultBase { isFetching: boolean isStale: boolean failureCount: number + canFetchMore?: boolean + markedForGarbageCollection: boolean + query: object + updatedAt: number refetch: ({ throwOnError }?: { throwOnError?: boolean }) => Promise } +export interface QueryIdleResult + extends QueryResultBase { + status: 'idle' + isIdle: true + isLoading: false + isSuccess: false + isError: false + data: undefined + error: null +} + export interface QueryLoadingResult extends QueryResultBase { status: 'loading' + isIdle: false isLoading: true isSuccess: false isError: false @@ -390,6 +314,7 @@ export interface QueryLoadingResult export interface QueryErrorResult extends QueryResultBase { status: 'error' + isIdle: false isError: true isLoading: false isSuccess: false @@ -399,6 +324,7 @@ export interface QueryErrorResult export interface QuerySuccessResult extends QueryResultBase { status: 'success' + isIdle: false isSuccess: true isLoading: false isError: false @@ -407,6 +333,7 @@ export interface QuerySuccessResult extends QueryResultBase { } export type QueryResult = + | QueryIdleResult | QueryLoadingResult | QueryErrorResult | QuerySuccessResult @@ -455,7 +382,8 @@ export interface InfiniteQueryResult isFetchingMore: false | 'previous' | 'next' canFetchMore: boolean | undefined fetchMore: ( - moreVariable?: TMoreVariable | false + moreVariable?: TMoreVariable | false, + options?: { previous: boolean } ) => Promise | undefined } @@ -484,6 +412,7 @@ export interface MutateOptions { error: TError | null, snapshotValue?: unknown ) => Promise | void + throwOnError?: boolean } export interface MutationOptions @@ -507,6 +436,10 @@ export interface MutationResultBase { status: 'idle' | 'loading' | 'error' | 'success' data: undefined | TResult error: undefined | null | TError + isIdle: boolean + isLoading: boolean + isSuccess: boolean + isError: boolean promise: Promise reset: () => void } @@ -516,6 +449,10 @@ export interface IdleMutationResult status: 'idle' data: undefined error: null + isIdle: true + isLoading: false + isSuccess: false + isError: false } export interface LoadingMutationResult @@ -523,6 +460,10 @@ export interface LoadingMutationResult status: 'loading' data: undefined error: undefined + isIdle: false + isLoading: true + isSuccess: false + isError: false } export interface ErrorMutationResult @@ -530,6 +471,10 @@ export interface ErrorMutationResult status: 'error' data: undefined error: TError + isIdle: false + isLoading: false + isSuccess: false + isError: true } export interface SuccessMutationResult @@ -537,6 +482,10 @@ export interface SuccessMutationResult status: 'success' data: TResult error: undefined + isIdle: false + isLoading: false + isSuccess: true + isError: false } export type MutationResult = @@ -570,65 +519,46 @@ export interface CachedQuery { clear(): void } +export type QueryKey = TKey | false | null | undefined + export interface QueryCache { prefetchQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: QueryKey, queryFn: QueryFunction, - config?: PrefetchQueryOptions + config?: QueryOptions, + prefetch?: PrefetchQueryOptions ): Promise prefetchQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: QueryKey, queryFn: QueryFunction, - config?: PrefetchQueryOptions + config?: QueryOptions, + prefetch?: PrefetchQueryOptions ): Promise prefetchQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: QueryKey, queryFn: QueryFunction, - config?: PrefetchQueryOptions + prefetch?: PrefetchQueryOptions, + config?: QueryOptions ): Promise prefetchQuery( - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined), + queryKey: QueryKey, queryFn: QueryFunction, - config?: PrefetchQueryOptions + prefetch?: PrefetchQueryOptions, + config?: QueryOptions ): Promise prefetchQuery({ queryKey, - queryFn, config, }: { - queryKey: - | TKey - | false - | null - | undefined - | (() => TKey | false | null | undefined) + queryKey: QueryKey queryFn: QueryFunction - config?: PrefetchQueryOptions + config?: QueryOptions + prefetch?: PrefetchQueryOptions }): Promise getQueryData(key: AnyQueryKey | string): T | undefined @@ -675,10 +605,12 @@ export interface QueryCache { ): void isFetching: number subscribe(callback: (queryCache: QueryCache) => void): () => void - clear(): void + clear(): void, + resetErrorBoundaries: () => void } export const queryCache: QueryCache +export const queryCaches: QueryCache[] export interface MakeQueryCacheOptions { frozen?: boolean @@ -719,12 +651,7 @@ export interface ReactQueryProviderConfig { useErrorBoundary?: boolean refetchOnWindowFocus?: boolean queryKeySerializerFn?: ( - queryKey: - | QueryKeyPart[] - | string - | false - | undefined - | (() => QueryKeyPart[] | string | false | undefined) + queryKey: QueryKeyPart[] | string | false | undefined ) => [string, QueryKeyPart[]] | [] } shared?: BaseSharedOptions diff --git a/types/test.ts b/types/test.ts index 4d8749f911..36e889e8e5 100644 --- a/types/test.ts +++ b/types/test.ts @@ -1,23 +1,66 @@ import { - useMutation, - useQuery, - usePaginatedQuery, + ReactQueryProviderConfig, + setConsole, useInfiniteQuery, useIsFetching, - setConsole, - ReactQueryProviderConfig, + useMutation, + usePaginatedQuery, + useQuery, + queryCache, } from 'react-query' +class FooError extends Error {} + +function resetErrorBoundaries() { + queryCache.resetErrorBoundaries // $ExpectType () => void +} + +function prefetchQuery() { + queryCache.prefetchQuery('queryKey', (key: string) => Promise.resolve()) + queryCache.prefetchQuery('queryKey', (key: string) => Promise.resolve(), { + retry: 1, + }) + queryCache.prefetchQuery( + 'queryKey', + (key: string) => + Math.random() > 0.5 + ? Promise.reject(new FooError()) + : Promise.resolve(123), + { onError: a => false }, + { throwOnError: false } + ) + queryCache.prefetchQuery('queryKey', (key: string) => Promise.resolve(), { + throwOnError: true, + }) + queryCache.prefetchQuery(['queryKey'], (key: string) => Promise.resolve(), { + throwOnError: true, + }) +} + function simpleQuery() { // Query - simple case - const querySimple = useQuery('todos', () => Promise.resolve('test')) + const querySimple = useQuery('todos', () => + Promise.resolve('test') + ) + querySimple.isFetchingMore // $ExpectError + querySimple.fetchMore // $ExpectError + + querySimple.canFetchMore // $ExpectType boolean | undefined querySimple.data // $ExpectType string | undefined querySimple.error // $ExpectType Error | null + querySimple.failureCount // $ExpectType number + querySimple.isError // $ExpectType boolean querySimple.isFetching // $ExpectType boolean + querySimple.isIdle // $ExpectType boolean + querySimple.isLoading // $ExpectType boolean + querySimple.isStale // $ExpectType boolean + querySimple.isSuccess // $ExpectType boolean + querySimple.markedForGarbageCollection // $ExpectType boolean + querySimple.query // $ExpectType object + querySimple.refetch // $ExpectType ({ throwOnError }?: { throwOnError?: boolean | undefined; } | undefined) => Promise querySimple.refetch() // $ExpectType Promise - querySimple.fetchMore // $ExpectError - querySimple.canFetchMore // $ExpectError - querySimple.isFetchingMore // $ExpectError + querySimple.status // $ExpectType "idle" | "loading" | "error" | "success" + querySimple.updatedAt // $ExpectType number } function queryWithVariables() { @@ -31,13 +74,23 @@ function queryWithVariables() { query.refetch() // $ExpectType Promise } +function queryWithReadonlyArray() { + useQuery( + ['key', 'a'] as const, + async ( + key, // $ExpectType "key" + other // $ExpectType "a" + ) => key + ) +} + function queryKeyArrayOrder() { // first element in the key must be not null/undefined - useQuery([null, 'a'], async (id, key) => id) // $ExpectError + useQuery([null, 'a'], async (key, other) => key) // $ExpectError - useQuery([10, 'a'], async (id, key) => id) - useQuery([false, 'a'], async (id, key) => id) - useQuery([{ complex: { obj: "yes" } }, 'a'], async (id, key) => id) + useQuery([10, 'a'], async (key, other) => key) + useQuery([false, 'a'], async (key, other) => key) + useQuery([{ complex: { obj: 'yes' } }, 'a'], async (key, other) => key) } function conditionalQuery(condition: boolean) { @@ -45,40 +98,52 @@ function conditionalQuery(condition: boolean) { Promise.resolve(10) const queryFn2 = () => Promise.resolve('test') - // Query with falsey query key + useQuery(() => 'foo', queryFn2, { enabled: condition }) // $ExpectError + + // Query with falsey enabled useQuery(['foo', { bar: 'baz' }], queryFn1, { enabled: condition }) useQuery(['foo', { bar: 'baz' }], queryFn2, { enabled: condition }) useQuery({ queryKey: ['foo', { bar: 'baz' }], queryFn: queryFn1, - config: { - enabled: condition, - }, + config: { enabled: condition }, }) } +function queryWithoutFn() { + useQuery('key') + useQuery(['key']) + + useQuery('key', { suspense: false }) // with QueryOptions + useQuery(['key'], { suspense: false }) // with QueryOptions + + useQuery({ queryKey: 'key' }) + useQuery({ queryKey: ['key'] }) + + useQuery({ queryKey: 'key', config: { suspense: false } }) // with QueryOptions + useQuery({ queryKey: ['key'], config: { suspense: false } }) // with QueryOptions +} + function queryWithObjectSyntax(condition: boolean) { useQuery({ queryKey: ['key'], - queryFn: async key => key, + queryFn: async ( + key // $ExpectType string + ) => key, }).data // $ExpectType string | undefined useQuery({ queryKey: ['key', 10], queryFn: async ( key, // $ExpectType string - id, // $ExpectType number - var1, // $ExpectType boolean - var2 // $ExpectType number + id // $ExpectType number ) => 'yay!', }).data // $ExpectType string | undefined useQuery({ queryKey: 'key', queryFn: async ( - key, // $ExpectType "key" - var1, // $ExpectType boolean - var2 // $ExpectType number + key // $ExpectType "key" ) => 'yay!', }).data // $ExpectType string | undefined @@ -87,25 +152,16 @@ function queryWithObjectSyntax(condition: boolean) { queryFn: async ( key // $ExpectType "key" ) => 10, - config: { - enabled: condition, - }, + config: { enabled: condition }, }).data // $ExpectType number | undefined } function queryWithNestedKey() { // Query with nested variabes - const queryNested = useQuery( - [ - 'key', - { - nested: { - props: [1, 2], - }, - }, - ], - (key, variables) => Promise.resolve(variables.nested.props[0]) - ) + const queryNested = useQuery(['key', { nested: { props: [1, 2] } }], ( + key, // $ExpectType string + variables // $ExpectType { nested: { props: number[]; }; } + ) => Promise.resolve(variables.nested.props[0])) queryNested.data // $ExpectType number | undefined } @@ -131,16 +187,9 @@ function queryWithComplexKeysAndVariables() { ) => 100 ).data // $ExpectType number | undefined - const longVariables: [boolean, ...object[]] = [true, {}] - useQuery( - ['key'], - longVariables, - async ( - key, // $ExpectType string - var1, // $ExpectType boolean - ...vars // $ExpectType object[] - ) => 100 - ).data // $ExpectType number | undefined + const longVariables = [true, {}, {}, {}] as const + const queryFn = async (key: string, var1: boolean, ...vars: Array<{}>) => 100 + useQuery(['key', ...longVariables] as const, queryFn).data // $ExpectType number | undefined // the following example cannot work properly, as it would require concatenating tuples with infinite tails. // ts-toolbelt library's `List.Concat` cannot do the job. It would be possible to do with `typescript-tuple` and additional trick. @@ -203,23 +252,18 @@ function paginatedQuery() { } } -function paginatedQueryWithObjectSyntax(condition: boolean) { +function paginatedQueryWithObjectSyntax() { usePaginatedQuery({ - queryKey: condition && ['key', { a: 10 }], - variables: [true], - queryFn: async (key, { a }, debug) => - key === 'key' && a === 10 && debug ? 'yes' : 'no', + queryKey: ['key', { a: 10 }], + queryFn: async (key, { a }) => (key === 'key' && a === 10 ? 'yes' : 'no'), }).latestData // $ExpectType "yes" | "no" | undefined usePaginatedQuery({ queryKey: 'key', - variables: [true], - queryFn: async (key, debug) => (key === 'key' && debug ? 'yes' : 'no'), + queryFn: async key => (key === 'key' ? 'yes' : 'no'), }).latestData // $ExpectType "yes" | "no" | undefined usePaginatedQuery({ - queryKey: condition && (() => condition && 'key'), - variables: [10], - queryFn: async (key, level) => - key === 'key' && level === 10 ? 'yes' : 'no', + queryKey: 'key', + queryFn: async key => (key === 'key' ? 'yes' : 'no'), }).latestData // $ExpectType "yes" | "no" | undefined } @@ -254,7 +298,7 @@ function simpleInfiniteQuery(condition: boolean) { }) useInfiniteQuery(['key'], fetchWithCursor, { getFetchMore }) useInfiniteQuery('key', fetchWithCursor, { getFetchMore }) - useInfiniteQuery(() => condition && 'key', fetchWithCursor, { getFetchMore }) + useInfiniteQuery('key', fetchWithCursor, { getFetchMore }) const infiniteQuery = useInfiniteQuery(['key'], fetchWithCursor, { getFetchMore, @@ -268,9 +312,10 @@ function simpleInfiniteQuery(condition: boolean) { infiniteQuery.data // $ExpectType number[][] infiniteQuery.fetchMore() // $ExpectType Promise | undefined infiniteQuery.fetchMore('next') // $ExpectType Promise | undefined + infiniteQuery.fetchMore('next', { previous: true }) // $ExpectType Promise | undefined } -function infiniteQueryWithObjectSyntax(condition: boolean) { +function infiniteQueryWithObjectSyntax() { useInfiniteQuery({ queryKey: ['key', 1], queryFn: async (key, id, next = 0) => ({ next: next + 1 }), @@ -279,7 +324,7 @@ function infiniteQueryWithObjectSyntax(condition: boolean) { }, }).data // $ExpectType { next: number; }[] useInfiniteQuery({ - queryKey: condition && (() => condition && ['key', 1]), + queryKey: ['key', 1], queryFn: async (key, id, next = 0) => ({ next: next + 1 }), config: { getFetchMore: (last: { next: number }) => last.next, // annotation on this type is required to infer the type @@ -296,7 +341,7 @@ function infiniteQueryWithObjectSyntax(condition: boolean) { }, }).data // $ExpectType { next: number; }[] useInfiniteQuery({ - queryKey: condition && (() => condition && ('key' as const)), + queryKey: 'key', queryFn: async ( key, // $ExpectType "key" next = 0 @@ -305,60 +350,57 @@ function infiniteQueryWithObjectSyntax(condition: boolean) { getFetchMore: (last: { next: number }) => last.next, // annotation on this type is required to infer the type }, }).data // $ExpectType { next: number; }[] -} - -function log(...args: any[]) {} - -function infiniteQueryWithVariables(condition: boolean) { - async function fetchWithCursor2( - key: string, - debuglog?: (...args: any[]) => void, - cursor?: string - ) { - if (debuglog) debuglog(key, cursor) - return [1, 2, 3] - } - function getFetchMore(last: number[], all: number[][]) { - return last.length ? String(all.length + 1) : false - } - useInfiniteQuery< - number[], - [string], - [undefined | ((...args: any[]) => void)], - string - >(['key'], [undefined], fetchWithCursor2, { - getFetchMore: (last, all) => 'next', - }) + useInfiniteQuery<{ next: number }, string, undefined>({ + queryKey: 'key', + }).data // $ExpectType { next: number; }[] - useInfiniteQuery(['key'], [log], fetchWithCursor2, { getFetchMore }) - useInfiniteQuery('key', [log], fetchWithCursor2, { getFetchMore }) - useInfiniteQuery(() => condition && 'key', [log], fetchWithCursor2, { - getFetchMore, - }) + useInfiniteQuery<{ next: number }, [string], undefined>({ + queryKey: ['key'], + }).data // $ExpectType { next: number; }[] } +function log(...args: any[]) {} + +// Simple mutation function simpleMutation() { - // Simple mutation const mutation = () => Promise.resolve(['foo', 'bar']) - const [mutate] = useMutation(mutation, { + const [mutate, mutationState] = useMutation(mutation, { onSuccess(result) { result // $ExpectType string[] }, + throwOnError: false, }) mutate() - mutate(undefined, { + mutate({ throwOnError: true }) + + mutate({ throwOnError: true, onSettled(result, error) { result // $ExpectType string[] | undefined error // $ExpectType Error | null }, + onError( + error // $ExpectType Error + ) {}, + onSuccess( + result // $ExpectType string[] + ) {}, }) - // Invalid mutatation funciton + // Invalid mutatation function useMutation((arg1: string, arg2: string) => Promise.resolve()) // $ExpectError useMutation((arg1: string) => null) // $ExpectError + + mutationState.data // $ExpectType string[] | undefined + mutationState.error // $ExpectType Error | null | undefined + mutationState.isError // $ExpectType boolean + mutationState.isIdle // $ExpectType boolean + mutationState.isLoading // $ExpectType boolean + mutationState.isSuccess // $ExpectType boolean + mutationState.reset // $ExpectType () => void + mutationState.status // $ExpectType "idle" | "loading" | "error" | "success" } function mutationWithVariables() { @@ -394,14 +436,22 @@ function helpers() { function globalConfig() { const globalConfig: ReactQueryProviderConfig = { - onError(err, snapshot) { - log('Error', err, snapshot) + queries: { + useErrorBoundary: true, + refetchOnWindowFocus: true, + }, + shared: { + suspense: true, }, - onMutate(variables) { - log(variables) + mutations: { + throwOnError: true, + useErrorBoundary: true, + onMutate: (variables: unknown) => Promise.resolve(), + onSuccess: (data: unknown, variables: unknown) => undefined, + onError: (err: Error, snapshotValue: unknown) => undefined, + onSettled: (data: unknown, error: Error | null, snapshotValue?: any) => + undefined, }, - suspense: true, - isDataEqual: (oldData, newData) => oldData === newData, } } @@ -483,4 +533,26 @@ function mutationStatusDiscriminatedUnion() { mutationState.data // $ExpectType string[] mutationState.error // $ExpectType undefined } + + if (mutationState.isIdle) { + mutationState.data // $ExpectType undefined + mutationState.error // $ExpectType null + } + + if (mutationState.isLoading) { + mutationState.data // $ExpectType undefined + // corrected + // mutationState.error; // $ExpectType null + mutationState.error // $ExpectType undefined + } + + if (mutationState.isError) { + mutationState.data // $ExpectType undefined + mutationState.error // $ExpectType Error + } + + if (mutationState.isSuccess) { + mutationState.data // $ExpectType string[] + mutationState.error // $ExpectType undefined + } } diff --git a/types/tslint.json b/types/tslint.json index 295142061d..c3f7e30b30 100644 --- a/types/tslint.json +++ b/types/tslint.json @@ -1,6 +1,7 @@ { "extends": "dtslint/dtslint.json", "rules": { - "semicolon": false + "semicolon": false, + "no-unnecessary-generics": false } } diff --git a/yarn.lock b/yarn.lock index aede54065e..a173fc9216 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1673,11 +1673,24 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.1.tgz#b6e98083f13faa1e5231bfa3bdb1b0feff536b6d" integrity sha512-boy4xPNEtiw6N3abRhBi/e7hNvy3Tt8E9ZRAQrwAGzoCGZS/1wjo9KY7JHhnfnEsG5wSjDbymCozUM9a3ea7OQ== +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + "@types/q@^1.5.1": version "1.5.2" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== +"@types/react@^16.9.41": + version "16.9.41" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.41.tgz#925137ee4d2ff406a0ecf29e8e9237390844002e" + integrity sha512-6cFei7F7L4wwuM+IND/Q2cV1koQUvJ8iSV+Gwn0c3kvABZ691g7sp3hfEQHOUBJtccl1gPi+EyNjMIl9nGA0ug== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + "@types/resolve@0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -2562,6 +2575,11 @@ cssstyle@^2.2.0: dependencies: cssom "~0.3.6" +csstype@^2.2.0: + version "2.6.10" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b" + integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w== + damerau-levenshtein@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz#780cf7144eb2e8dbd1c3bb83ae31100ccc31a414" @@ -6856,6 +6874,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@^3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"