import * as React from 'react'; import { QueryResponse } from 'react-fetching-library'; const transformPayload = (payload: FROM | undefined, status: number | undefined, adapter: (from: FROM, status) => TO): TO | undefined => { if (payload) { return adapter(payload, status); } return payload as any; }; type ExpectedQueryResponse = QueryResponse & { query: (...args: Array) => Promise>; } type ExpectedMutateResponse = QueryResponse & { mutate: (...args: Array) => Promise>; } type UseTransformQueryResponseTypeQuery< FROM, USE_QUERY_RESPONSE_FROM extends ExpectedQueryResponse, TO > = Omit & { query: (...args: Parameters) => Promise>; payload: undefined | TO; }; type UseTransformQueryResponseTypeMutation< FROM, USE_QUERY_RESPONSE_FROM extends ExpectedMutateResponse, TO > = Omit & { mutate: (...args: Parameters) => Promise>; payload: undefined | TO; }; interface UseTransformQueryResponseType { >(queryResponse: USE_QUERY_RESPONSE_FROM, adapter: (from: FROM) => TO): UseTransformQueryResponseTypeQuery; >(queryResponse: USE_MUTATE_RESPONSE_FROM, adapter: (from: FROM) => TO): UseTransformQueryResponseTypeMutation; } const isQuery = (response): response is ExpectedQueryResponse => { return response.hasOwnProperty('query'); }; const isMutate = (response): response is ExpectedMutateResponse => { return response.hasOwnProperty('mutate'); }; export const useTransformQueryResponse: UseTransformQueryResponseType = ( queryResponse: USE_QUERY_RESPONSE_FROM, adapter: (from: FROM) => TO ) => { if (!isQuery(queryResponse) && !isMutate(queryResponse)) { throw new Error('Invalid query response provided to useTransformQueryResponse'); } const response: ExpectedQueryResponse | ExpectedMutateResponse = queryResponse; const { payload, status } = response; const transformedPayload = React.useMemo( () => transformPayload(payload, status, adapter), [ adapter, payload, status ] ); const field = isQuery(queryResponse) ? 'query' : 'mutate'; const func = isQuery(queryResponse) ? queryResponse.query : queryResponse.mutate; const transformedQuery = React.useCallback((...args: Parameters): Promise> => { return func(...args).then(response => { return { ...response, payload: transformPayload(response.payload, response.status, adapter) }; }); }, [ func, adapter ]); return { ...queryResponse, payload: transformedPayload, [field]: transformedQuery }; };