DefinitelyTyped/types/react-query/react-query-tests.ts
Igor Oleinikov 2ea0ccd01f
[react-query] Update API to 1.10.0 (#43438)
* [react-query] Update API to 1.10.0
- breaking changes

* Make use of extra variables
* Fixing lint errors
* Complete useInfiniteQuery
* Add global config
* Add queryCache
* Allow keys and variables with infinite tails
* Add discriminated unions for base and paginated queries
* Discriminated union for mutation result
* Require first key element to be a string subtype
2020-03-30 15:23:50 -07:00

317 lines
11 KiB
TypeScript

import {
useMutation,
useQuery,
usePaginatedQuery,
useInfiniteQuery,
useIsFetching,
setConsole,
ReactQueryProviderConfig,
} from 'react-query';
function simpleQuery() {
// Query - simple case
const querySimple = useQuery('todos', () => Promise.resolve('test'));
querySimple.data; // $ExpectType string | undefined
querySimple.error; // $ExpectType unknown
querySimple.isFetching; // $ExpectType boolean
querySimple.refetch(); // $ExpectType Promise<string>
querySimple.fetchMore; // $ExpectError
querySimple.canFetchMore; // $ExpectError
querySimple.isFetchingMore; // $ExpectError
}
function queryWithVariables() {
// Query Variables
const param = 'test';
const queryVariables = useQuery(['todos', { param }, 10], (key, variables, id) =>
Promise.resolve(variables.param === 'test'),
);
queryVariables.data; // $ExpectType boolean | undefined
queryVariables.refetch(); // $ExpectType Promise<boolean>
queryVariables.refetch({ force: true }); // $ExpectType Promise<boolean>
}
function invalidSimpleQuery() {
// first element in the key must be a string
useQuery([10, 'a'], async (id, key) => id); // $ExpectError
}
function conditionalQuery(condition: boolean) {
const queryFn1 = (name: string, params: { bar: string }) => Promise.resolve(10);
const queryFn2 = () => Promise.resolve('test');
// Query with falsey query key
useQuery(condition && ['foo', { bar: 'baz' }], queryFn1);
useQuery(condition && ['foo', { bar: 'baz' }], queryFn2);
useQuery({
queryKey: condition && ['foo', { bar: 'baz' }],
queryFn: queryFn1,
});
// Query with query key function
useQuery(() => ['foo', { bar: 'baz' }], queryFn1);
useQuery(() => ['foo', { bar: 'baz' }], queryFn2);
}
function queryWithNestedKey() {
// Query with nested variabes
const queryNested = useQuery(
[
'key',
{
nested: {
props: [1, 2],
},
},
],
(key, variables) => Promise.resolve(variables.nested.props[0]),
);
queryNested.data; // $ExpectType number | undefined
}
function queryWithComplexKeysAndVariables() {
useQuery(['key', { a: 1 }], [{ b: { x: 1 } }, { c: { x: 1 } }], (
key1, // $ExpectType string
key2, // ExpectType { a: number }
var1, // $ExpectType { b: { x: number; }; }
var2, // $ExpectType { c: { x: number; }; }
) => Promise.resolve(key1 === 'key' && key2.a === 1 && var1.b.x === 1 && var2.c.x === 1));
// custom key
const longKey: [string, ...number[]] = ['key', 1, 2, 3, 4, 5];
useQuery(
longKey,
async (
key, // $ExpectType string
...ids // $ExpectType number[]
) => 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
// 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.
// useQuery<number, typeof longKey, typeof longVariables>(longKey, longVariables, async (
// key, // $ExpectType string // <-- currently boolean?!
// keyOrVar, // $ExpectType number | boolean // <-- currently object
// ...rest // $ExpectType number | object // <-- currently object[]
// ) => 100).data; // $ExpectType number | undefined
}
function paginatedQuery() {
// Paginated mode
const queryPaginated = usePaginatedQuery('key', () => Promise.resolve({ data: [1, 2, 3], next: true }), {
refetchInterval: 1000,
});
queryPaginated.resolvedData; // $ExpectType { data: number[]; next: boolean; } | undefined
queryPaginated.latestData; // $ExpectType { data: number[]; next: boolean; } | undefined
queryPaginated.data; // $ExpectError
// Discriminated union over status
if (queryPaginated.status === 'loading') {
queryPaginated.resolvedData; // $ExpectType { data: number[]; next: boolean; } | undefined
queryPaginated.latestData; // $ExpectType { data: number[]; next: boolean; } | undefined
queryPaginated.error; // $ExpectType unknown
}
if (queryPaginated.status === 'error') {
queryPaginated.resolvedData; // $ExpectType { data: number[]; next: boolean; } | undefined
queryPaginated.latestData; // $ExpectType { data: number[]; next: boolean; } | undefined
queryPaginated.error; // $ExpectType unknown
}
if (queryPaginated.status === 'success') {
queryPaginated.resolvedData; // $ExpectType { data: number[]; next: boolean; }
queryPaginated.latestData; // $ExpectType { data: number[]; next: boolean; }
queryPaginated.error; // $ExpectType null
}
}
function simpleInfiniteQuery(condition: boolean) {
async function fetchWithCursor(key: string, cursor?: string) {
return [1, 2, 3];
}
function getFetchMore(last: number[], all: number[][]) {
return last.length ? String(all.length + 1) : false;
}
useInfiniteQuery<number[], [string], string>(['key'], fetchWithCursor, {
getFetchMore: (
last, // $ExpectType number[]
all, // $ExpectType number[][]
) => 'next',
});
useInfiniteQuery(['key'], fetchWithCursor, { getFetchMore });
useInfiniteQuery('key', fetchWithCursor, { getFetchMore });
useInfiniteQuery(() => condition && 'key', fetchWithCursor, { getFetchMore });
const infiniteQuery = useInfiniteQuery(['key'], fetchWithCursor, { getFetchMore });
// The next example does not work; the type for cursor does not get inferred.
// useInfiniteQuery(['key'], fetchWithCursor, {
// getFetchMore: (last, all) => 'string',
// });
infiniteQuery.data; // $ExpectType number[][]
infiniteQuery.fetchMore(); // $ExpectType Promise<number[][]> | undefined
infiniteQuery.fetchMore('next'); // $ExpectType Promise<number[][]> | undefined
}
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(['key'], [log], fetchWithCursor2, { getFetchMore });
useInfiniteQuery('key', [log], fetchWithCursor2, { getFetchMore });
useInfiniteQuery(() => condition && 'key', [log], fetchWithCursor2, { getFetchMore });
}
function simpleMutation() {
// Simple mutation
const mutation = () => Promise.resolve(['foo', 'bar']);
const [mutate] = useMutation(mutation, {
onSuccess(result) {
result; // $ExpectType string[]
},
});
mutate();
mutate(undefined, {
throwOnError: true,
onSettled(result, error) {
result; // $ExpectType string[] | undefined
error; // $ExpectType unknown
},
});
// Invalid mutatation funciton
useMutation((arg1: string, arg2: string) => Promise.resolve()); // $ExpectError
useMutation((arg1: string) => null); // $ExpectError
}
function mutationWithVariables() {
// Mutation with variables
const [mutateWithVars] = useMutation(({ param }: { param: number }) => Promise.resolve(Boolean(param)), {
useErrorBoundary: true,
onMutate(variables) {
variables; // $ExpectType { param: number; }
return { snapshot: variables.param };
},
});
mutateWithVars(
{ param: 1 },
{
async onSuccess(data) {
data; // $ExpectType boolean
},
},
);
mutateWithVars({ param: 'test' }); // $ExpectError
}
function helpers() {
useIsFetching(); // $ExpectType number
setConsole({ log, error: log, warn: log });
}
function globalConfig() {
const globalConfig: ReactQueryProviderConfig = {
onError(err, snapshot) {
log('Error', err, snapshot);
},
onMutate(variables) {
log(variables);
},
suspense: true,
};
}
function dataDiscriminatedUnion() {
// Query Variables
const param = 'test';
const queryResult = useQuery(['todos', { param }], (key, variables) => Promise.resolve([param]));
queryResult.data; // $ExpectType string[] | undefined
// Discriminated union over status
if (queryResult.status === 'loading') {
queryResult.data; // $ExpectType string[] | undefined
queryResult.error; // $ExpectType unknown
}
if (queryResult.status === 'error') {
// disabled
queryResult.data; // $ExpectType string[] | undefined
queryResult.error; // $ExpectType unknown
}
if (queryResult.status === 'success') {
// disabled
queryResult.data; // $ExpectType string[]
queryResult.error; // $ExpectType null
}
}
function mutationStatusDiscriminatedUnion() {
const mutation = () => Promise.resolve(['foo', 'bar']);
const [mutate, mutationState] = useMutation(mutation);
mutate();
// enabled
// TODO: handle invalid argument passed to mutationFn
// mutate('arg'); // $ExpectError
mutate('arg'); // $ExpectError
mutationState.data; // $ExpectType string[] | undefined
// Discriminated union over status
if (mutationState.status === 'idle') {
mutationState.data; // $ExpectType undefined
mutationState.error; // $ExpectType null
}
if (mutationState.status === 'loading') {
mutationState.data; // $ExpectType undefined
// corrected
// mutationState.error; // $ExpectType null
mutationState.error; // $ExpectType undefined
}
if (mutationState.status === 'error') {
mutationState.data; // $ExpectType undefined
mutationState.error; // $ExpectType unknown
}
if (mutationState.status === 'success') {
mutationState.data; // $ExpectType string[]
mutationState.error; // $ExpectType undefined
}
}