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 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 queryVariables.refetch({ force: true }); // $ExpectType Promise } 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(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(['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 | undefined infiniteQuery.fetchMore('next'); // $ExpectType Promise | 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 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 } }