From ceb9e7338ee8745e41c9720a7cb2a839e4a2883d Mon Sep 17 00:00:00 2001 From: Igor Oleinikov Date: Fri, 3 Apr 2020 17:16:22 -0700 Subject: [PATCH] [react-query] Few improvements (#43568) * [react-query] Few improvements - allow single string key in object syntax - reorder overloads to fix intellisense * Addressing PR feedback --- types/react-query/index.d.ts | 101 +++++++++++++++++------- types/react-query/react-query-tests.ts | 105 +++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 30 deletions(-) diff --git a/types/react-query/index.d.ts b/types/react-query/index.d.ts index ba52096436..1b17ce8efe 100644 --- a/types/react-query/index.d.ts +++ b/types/react-query/index.d.ts @@ -11,15 +11,39 @@ import * as React from 'react'; import * as _ from 'ts-toolbelt'; // overloaded useQuery function +export function useQuery({ + queryKey, + variables, + queryFn, + config, +}: { + queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined); + variables?: TVariables; + queryFn: QueryFunctionWithVariables; + config?: QueryOptions; +}): QueryResult; + +export function useQuery({ + queryKey, + variables, + queryFn, + config, +}: { + queryKey: TSingleKey | false | null | undefined | (() => TSingleKey | false | null | undefined); + variables?: TVariables; + queryFn: QueryFunctionWithVariables; + config?: QueryOptions; +}): QueryResult; + export function useQuery( queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined), queryFn: QueryFunction, config?: QueryOptions, ): QueryResult; -export function useQuery( - queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined), - queryFn: QueryFunction, +export function useQuery( + queryKey: TSingleKey | false | null | undefined | (() => TSingleKey | false | null | undefined), + queryFn: QueryFunction, config?: QueryOptions, ): QueryResult; @@ -37,7 +61,8 @@ export function useQuery, ): QueryResult; -export function useQuery({ +// usePaginatedQuery +export function usePaginatedQuery({ queryKey, variables, queryFn, @@ -47,9 +72,20 @@ export function useQuery; config?: QueryOptions; -}): QueryResult; +}): PaginatedQueryResult; + +export function usePaginatedQuery({ + queryKey, + variables, + queryFn, + config, +}: { + queryKey: TSingleKey | false | null | undefined | (() => TSingleKey | false | null | undefined); + variables?: TVariables; + queryFn: QueryFunctionWithVariables; + config?: QueryOptions; +}): PaginatedQueryResult; -// usePaginatedQuery export function usePaginatedQuery( queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined), queryFn: QueryFunction, @@ -76,7 +112,13 @@ export function usePaginatedQuery, ): PaginatedQueryResult; -export function usePaginatedQuery({ +// useInfiniteQuery +export function useInfiniteQuery< + TResult, + TKey extends AnyQueryKey, + TMoreVariable, + TVariables extends AnyVariables = [] +>({ queryKey, variables, queryFn, @@ -84,11 +126,27 @@ export function usePaginatedQuery TKey | false | null | undefined); variables?: TVariables; - queryFn: QueryFunctionWithVariables; - config?: QueryOptions; -}): PaginatedQueryResult; + queryFn: InfiniteQueryFunctionWithVariables; + config?: InfiniteQueryOptions; +}): InfiniteQueryResult; + +export function useInfiniteQuery< + TResult, + TSingleKey extends string, + TMoreVariable, + TVariables extends AnyVariables = [] +>({ + queryKey, + variables, + queryFn, + config, +}: { + queryKey: TSingleKey | false | null | undefined | (() => TSingleKey | false | null | undefined); + variables?: TVariables; + queryFn: InfiniteQueryFunctionWithVariables; + config?: InfiniteQueryOptions; +}): InfiniteQueryResult; -// useInfiniteQuery export function useInfiniteQuery( queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined), queryFn: InfiniteQueryFunction, @@ -115,23 +173,6 @@ export function useInfiniteQuery, ): InfiniteQueryResult; -export function useInfiniteQuery< - TResult, - TKey extends AnyQueryKey, - TMoreVariable, - TVariables extends AnyVariables = [] ->({ - queryKey, - variables, - queryFn, - config, -}: { - queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined); - variables?: TVariables; - queryFn: InfiniteQueryFunctionWithVariables; - config?: InfiniteQueryOptions; -}): InfiniteQueryResult; - export type QueryKeyPart = string | object | boolean | number | null | readonly QueryKeyPart[] | null | undefined; export type AnyQueryKey = readonly [string, ...QueryKeyPart[]]; // this forces the key to be inferred as a tuple export type AnyVariables = readonly [] | readonly [any, ...any[]]; // this forces the variables to be inferred as a tuple @@ -181,10 +222,10 @@ export interface BaseQueryOptions { export interface QueryOptions extends BaseQueryOptions { onSuccess?: (data: TResult) => void; onSettled?: (data: TResult | undefined, error: unknown | null) => void; - initialData?: TResult; + initialData?: TResult | (() => TResult | undefined); } -export interface InfiniteQueryOptions extends QueryOptions { +export interface InfiniteQueryOptions extends QueryOptions { getFetchMore: (lastPage: TResult, allPages: TResult[]) => TMoreVariable | false; } diff --git a/types/react-query/react-query-tests.ts b/types/react-query/react-query-tests.ts index 7cd42d2b6d..9d9beed244 100644 --- a/types/react-query/react-query-tests.ts +++ b/types/react-query/react-query-tests.ts @@ -54,6 +54,41 @@ function conditionalQuery(condition: boolean) { useQuery(() => ['foo', { bar: 'baz' }], queryFn2); } +function queryWithObjectSyntax(condition: boolean) { + useQuery({ + queryKey: ['key'], + queryFn: async key => key, + }).data; // $ExpectType string | undefined + + useQuery({ + queryKey: ['key', 10], + variables: [true, 20], + queryFn: async ( + key, // $ExpectType string + id, // $ExpectType number + var1, // $ExpectType boolean + var2, // $ExpectType number + ) => 'yay!', + }).data; // $ExpectType string | undefined + + useQuery({ + queryKey: 'key', + variables: [true, 20], + queryFn: async ( + key, // $ExpectType "key" + var1, // $ExpectType boolean + var2, // $ExpectType number + ) => 'yay!', + }).data; // $ExpectType string | undefined + + useQuery({ + queryKey: condition && 'key', + queryFn: async ( + key, // $ExpectType "key" + ) => 10, + }).data; // $ExpectType number | undefined +} + function queryWithNestedKey() { // Query with nested variabes const queryNested = useQuery( @@ -137,6 +172,24 @@ function paginatedQuery() { } } +function paginatedQueryWithObjectSyntax(condition: boolean) { + usePaginatedQuery({ + queryKey: condition && ['key', { a: 10 }], + variables: [true], + queryFn: async (key, { a }, debug) => (key === 'key' && a === 10 && debug ? 'yes' : 'no'), + }).latestData; // $ExpectType "yes" | "no" | undefined + usePaginatedQuery({ + queryKey: 'key', + variables: [true], + queryFn: async (key, debug) => (key === 'key' && debug ? 'yes' : 'no'), + }).latestData; // $ExpectType "yes" | "no" | undefined + usePaginatedQuery({ + queryKey: condition && (() => condition && 'key'), + variables: [10], + queryFn: async (key, level) => (key === 'key' && level === 10 ? 'yes' : 'no'), + }).latestData; // $ExpectType "yes" | "no" | undefined +} + function simpleInfiniteQuery(condition: boolean) { async function fetchWithCursor(key: string, cursor?: string) { return [1, 2, 3]; @@ -150,6 +203,21 @@ function simpleInfiniteQuery(condition: boolean) { last, // $ExpectType number[] all, // $ExpectType number[][] ) => 'next', + // type of data in success is the array of results + onSuccess( + data, // $ExpectType number[][] + ) {}, + onSettled( + data, // $ExpectType number[][] | undefined + error, // $ExpectType unknown + ) {}, + initialData: () => + condition + ? [ + [1, 2], + [2, 3], + ] + : undefined, }); useInfiniteQuery(['key'], fetchWithCursor, { getFetchMore }); useInfiniteQuery('key', fetchWithCursor, { getFetchMore }); @@ -167,6 +235,43 @@ function simpleInfiniteQuery(condition: boolean) { infiniteQuery.fetchMore('next'); // $ExpectType Promise | undefined } +function infiniteQueryWithObjectSyntax(condition: boolean) { + useInfiniteQuery({ + 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 + }, + }).data; // $ExpectType { next: number; }[] + useInfiniteQuery({ + queryKey: condition && (() => condition && ['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 + }, + }).data; // $ExpectType { next: number; }[] + useInfiniteQuery({ + queryKey: 'key', + queryFn: async ( + key, // $ExpectType "key" + next = 0, + ) => ({ next: next + 1 }), + config: { + getFetchMore: (last: { next: number }) => last.next, // annotation on this type is required to infer the type + }, + }).data; // $ExpectType { next: number; }[] + useInfiniteQuery({ + queryKey: condition && (() => condition && ('key' as const)), + queryFn: async ( + key, // $ExpectType "key" + next = 0, + ) => ({ next: next + 1 }), + config: { + 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) {