[react-query] Few improvements (#43568)

* [react-query] Few improvements
- allow single string key in object syntax
- reorder overloads to fix intellisense

* Addressing PR feedback
This commit is contained in:
Igor Oleinikov
2020-04-03 17:16:22 -07:00
committed by GitHub
parent 13ff340e33
commit ceb9e7338e
2 changed files with 176 additions and 30 deletions
+71 -30
View File
@@ -11,15 +11,39 @@ import * as React from 'react';
import * as _ from 'ts-toolbelt';
// overloaded useQuery function
export function useQuery<TResult, TKey extends AnyQueryKey, TVariables extends AnyVariables = []>({
queryKey,
variables,
queryFn,
config,
}: {
queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined);
variables?: TVariables;
queryFn: QueryFunctionWithVariables<TResult, TKey, TVariables>;
config?: QueryOptions<TResult>;
}): QueryResult<TResult>;
export function useQuery<TResult, TSingleKey extends string, TVariables extends AnyVariables = []>({
queryKey,
variables,
queryFn,
config,
}: {
queryKey: TSingleKey | false | null | undefined | (() => TSingleKey | false | null | undefined);
variables?: TVariables;
queryFn: QueryFunctionWithVariables<TResult, [TSingleKey], TVariables>;
config?: QueryOptions<TResult>;
}): QueryResult<TResult>;
export function useQuery<TResult, TKey extends AnyQueryKey>(
queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined),
queryFn: QueryFunction<TResult, TKey>,
config?: QueryOptions<TResult>,
): QueryResult<TResult>;
export function useQuery<TResult, TKey extends string>(
queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined),
queryFn: QueryFunction<TResult, [TKey]>,
export function useQuery<TResult, TSingleKey extends string>(
queryKey: TSingleKey | false | null | undefined | (() => TSingleKey | false | null | undefined),
queryFn: QueryFunction<TResult, [TSingleKey]>,
config?: QueryOptions<TResult>,
): QueryResult<TResult>;
@@ -37,7 +61,8 @@ export function useQuery<TResult, TKey extends string, TVariables extends AnyVar
config?: QueryOptions<TResult>,
): QueryResult<TResult>;
export function useQuery<TResult, TKey extends AnyQueryKey, TVariables extends AnyVariables = []>({
// usePaginatedQuery
export function usePaginatedQuery<TResult, TKey extends AnyQueryKey, TVariables extends AnyVariables = []>({
queryKey,
variables,
queryFn,
@@ -47,9 +72,20 @@ export function useQuery<TResult, TKey extends AnyQueryKey, TVariables extends A
variables?: TVariables;
queryFn: QueryFunctionWithVariables<TResult, TKey, TVariables>;
config?: QueryOptions<TResult>;
}): QueryResult<TResult>;
}): PaginatedQueryResult<TResult>;
export function usePaginatedQuery<TResult, TSingleKey extends string, TVariables extends AnyVariables = []>({
queryKey,
variables,
queryFn,
config,
}: {
queryKey: TSingleKey | false | null | undefined | (() => TSingleKey | false | null | undefined);
variables?: TVariables;
queryFn: QueryFunctionWithVariables<TResult, [TSingleKey], TVariables>;
config?: QueryOptions<TResult>;
}): PaginatedQueryResult<TResult>;
// usePaginatedQuery
export function usePaginatedQuery<TResult, TKey extends AnyQueryKey>(
queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined),
queryFn: QueryFunction<TResult, TKey>,
@@ -76,7 +112,13 @@ export function usePaginatedQuery<TResult, TKey extends string, TVariables exten
config?: QueryOptions<TResult>,
): PaginatedQueryResult<TResult>;
export function usePaginatedQuery<TResult, TKey extends AnyQueryKey, TVariables extends AnyVariables = []>({
// useInfiniteQuery
export function useInfiniteQuery<
TResult,
TKey extends AnyQueryKey,
TMoreVariable,
TVariables extends AnyVariables = []
>({
queryKey,
variables,
queryFn,
@@ -84,11 +126,27 @@ export function usePaginatedQuery<TResult, TKey extends AnyQueryKey, TVariables
}: {
queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined);
variables?: TVariables;
queryFn: QueryFunctionWithVariables<TResult, TKey, TVariables>;
config?: QueryOptions<TResult>;
}): PaginatedQueryResult<TResult>;
queryFn: InfiniteQueryFunctionWithVariables<TResult, TKey, TVariables, TMoreVariable>;
config?: InfiniteQueryOptions<TResult, TMoreVariable>;
}): InfiniteQueryResult<TResult, TMoreVariable>;
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<TResult, [TSingleKey], TVariables, TMoreVariable>;
config?: InfiniteQueryOptions<TResult, TMoreVariable>;
}): InfiniteQueryResult<TResult, TMoreVariable>;
// useInfiniteQuery
export function useInfiniteQuery<TResult, TKey extends AnyQueryKey, TMoreVariable>(
queryKey: TKey | false | null | undefined | (() => TKey | false | null | undefined),
queryFn: InfiniteQueryFunction<TResult, TKey, TMoreVariable>,
@@ -115,23 +173,6 @@ export function useInfiniteQuery<TResult, TKey extends string, TVariables extend
config?: InfiniteQueryOptions<TResult, TMoreVariable>,
): InfiniteQueryResult<TResult, TMoreVariable>;
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<TResult, TKey, TVariables, TMoreVariable>;
config?: InfiniteQueryOptions<TResult, TMoreVariable>;
}): InfiniteQueryResult<TResult, TMoreVariable>;
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<TResult> extends BaseQueryOptions {
onSuccess?: (data: TResult) => void;
onSettled?: (data: TResult | undefined, error: unknown | null) => void;
initialData?: TResult;
initialData?: TResult | (() => TResult | undefined);
}
export interface InfiniteQueryOptions<TResult, TMoreVariable> extends QueryOptions<TResult> {
export interface InfiniteQueryOptions<TResult, TMoreVariable> extends QueryOptions<TResult[]> {
getFetchMore: (lastPage: TResult, allPages: TResult[]) => TMoreVariable | false;
}
+105
View File
@@ -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<number[][]> | 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) {