Skip to content

Commit

Permalink
feat: improve useAsyncFn and useAsync typings
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich authored Dec 30, 2019
2 parents 57e1744 + 733cf9b commit 85967e2
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 20 deletions.
10 changes: 4 additions & 6 deletions src/useAsync.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { DependencyList, useEffect } from 'react';
import useAsyncFn from './useAsyncFn';
import { FnReturningPromise } from './util';

export { AsyncState, AsyncFn } from './useAsyncFn';
export { AsyncState, AsyncFnReturn } from './useAsyncFn';

export default function useAsync<Result = any, Args extends any[] = any[]>(
fn: (...args: Args | []) => Promise<Result>,
deps: DependencyList = []
) {
const [state, callback] = useAsyncFn<Result, Args>(fn, deps, {
export default function useAsync<T extends FnReturningPromise>(fn: T, deps: DependencyList = []) {
const [state, callback] = useAsyncFn(fn, deps, {
loading: true,
});

Expand Down
25 changes: 12 additions & 13 deletions src/useAsyncFn.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DependencyList, useCallback, useState, useRef } from 'react';
import useMountedState from './useMountedState';
import { FnReturningPromise, PromiseType } from './util';

export type AsyncState<T> =
| {
Expand All @@ -18,22 +19,20 @@ export type AsyncState<T> =
value: T;
};

export type AsyncFn<Result = any, Args extends any[] = any[]> = [
AsyncState<Result>,
(...args: Args | []) => Promise<Result>
];
type StateFromFnReturningPromise<T extends FnReturningPromise> = AsyncState<PromiseType<ReturnType<T>>>;

export default function useAsyncFn<Result = any, Args extends any[] = any[]>(
fn: (...args: Args | []) => Promise<Result>,
export type AsyncFnReturn<T extends FnReturningPromise = FnReturningPromise> = [StateFromFnReturningPromise<T>, T];

export default function useAsyncFn<T extends FnReturningPromise>(
fn: T,
deps: DependencyList = [],
initialState: AsyncState<Result> = { loading: false }
): AsyncFn<Result, Args> {
initialState: StateFromFnReturningPromise<T> = { loading: false }
): AsyncFnReturn<T> {
const lastCallId = useRef(0);
const [state, set] = useState<AsyncState<Result>>(initialState);

const isMounted = useMountedState();
const [state, set] = useState<StateFromFnReturningPromise<T>>(initialState);

const callback = useCallback((...args: Args | []) => {
const callback = useCallback((...args: Parameters<T>): ReturnType<T> => {
const callId = ++lastCallId.current;
set({ loading: true });

Expand All @@ -48,8 +47,8 @@ export default function useAsyncFn<Result = any, Args extends any[] = any[]>(

return error;
}
);
) as ReturnType<T>;
}, deps);

return [state, callback];
return [state, (callback as unknown) as T];
}
4 changes: 4 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ export const isClient = typeof window === 'object';
export const on = (obj: any, ...args: any[]) => obj.addEventListener(...args);

export const off = (obj: any, ...args: any[]) => obj.removeEventListener(...args);

export type FnReturningPromise = (...args: any[]) => Promise<any>;

export type PromiseType<P extends Promise<any>> = P extends Promise<infer T> ? T : never;
2 changes: 1 addition & 1 deletion tests/useAsync.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ describe('useAsync', () => {
hook = renderHook(
({ fn, counter }) => {
const callback = useCallback(() => fn(counter), [counter]);
return useAsync<string>(callback, [callback]);
return useAsync<any>(callback, [callback]);
},
{
initialProps: {
Expand Down

0 comments on commit 85967e2

Please sign in to comment.