Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TypeScript] Fix onSuccess / onFailure types #5853

Merged
merged 2 commits into from
Feb 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import {
useRedirect,
RedirectionSideEffect,
} from '../../sideEffect';
import { Record, MutationMode } from '../../types';
import { OnFailure, OnSuccess } from '../saveModifiers';
import { Record, MutationMode, OnFailure, OnSuccess } from '../../types';
import { useResourceContext } from '../../core';

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import {
useRedirect,
RedirectionSideEffect,
} from '../../sideEffect';
import { Record } from '../../types';
import { OnFailure, OnSuccess } from '../saveModifiers';
import { Record, OnFailure, OnSuccess } from '../../types';
import { useResourceContext } from '../../core';

/**
Expand Down
9 changes: 2 additions & 7 deletions packages/ra-core/src/controller/details/SaveContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ import { createContext, MutableRefObject, useContext, useMemo } from 'react';
import pick from 'lodash/pick';

import { RedirectionSideEffect } from '../../sideEffect';
import { Record } from '../../types';
import {
OnFailure,
OnSuccess,
SideEffectContextValue,
TransformData,
} from '../saveModifiers';
import { Record, OnFailure, OnSuccess } from '../../types';
import { SideEffectContextValue, TransformData } from '../saveModifiers';

interface SaveContextValue extends SideEffectContextValue {
onFailureRef?: MutableRefObject<OnFailure>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import {
RedirectionSideEffect,
} from '../../sideEffect';
import {
OnSuccess,
SetOnSuccess,
OnFailure,
SetOnFailure,
TransformData,
SetTransformData,
Expand All @@ -24,7 +22,7 @@ import {
import { useTranslate } from '../../i18n';
import useVersion from '../useVersion';
import { CRUD_CREATE } from '../../actions';
import { Record } from '../../types';
import { Record, OnSuccess, OnFailure } from '../../types';
import { useResourceContext } from '../../core';

export interface CreateProps<RecordType extends Omit<Record, 'id'> = Record> {
Expand Down
10 changes: 7 additions & 3 deletions packages/ra-core/src/controller/details/useEditController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import inflection from 'inflection';

import useVersion from '../useVersion';
import { useCheckMinimumRequiredProps } from '../checkMinimumRequiredProps';
import { Record, Identifier, MutationMode } from '../../types';
import {
Record,
Identifier,
MutationMode,
OnSuccess,
OnFailure,
} from '../../types';
import {
useNotify,
useRedirect,
Expand All @@ -14,9 +20,7 @@ import { useGetOne, useUpdate } from '../../dataProvider';
import { useTranslate } from '../../i18n';
import { CRUD_GET_ONE, CRUD_UPDATE } from '../../actions';
import {
OnSuccess,
SetOnSuccess,
OnFailure,
SetOnFailure,
TransformData,
SetTransformData,
Expand Down
3 changes: 1 addition & 2 deletions packages/ra-core/src/controller/saveModifiers.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { createContext, useRef } from 'react';
import { OnSuccess, OnFailure } from '../types';

export const SideEffectContext = createContext<SideEffectContextValue>({});

Expand Down Expand Up @@ -67,9 +68,7 @@ export const useSaveModifiers = ({
};
};

export type OnSuccess = (response: any) => void;
export type SetOnSuccess = (onSuccess: OnSuccess) => void;
export type OnFailure = (error: { message?: string }) => void;
export type SetOnFailure = (onFailure: OnFailure) => void;
export type TransformData = (data: any) => any | Promise<any>;
export type SetTransformData = (transform: TransformData) => void;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dispatch } from 'redux';
import { DataProvider } from '../../types';
import { DataProvider, OnSuccess, OnFailure } from '../../types';

export interface QueryFunctionParams {
/** The fetch type, e.g. `UPDATE_MANY` */
Expand All @@ -8,9 +8,12 @@ export interface QueryFunctionParams {
resource: string;
/** The root action name, e.g. `CRUD_GET_MANY` */
action: string;
rest: any;
onSuccess?: (args?: any) => void;
onFailure?: (error: any) => void;
rest?: {
fetch?: string;
meta?: object;
};
onSuccess?: OnSuccess;
onFailure?: OnFailure;
dataProvider: DataProvider;
dispatch: Dispatch;
logoutIfAccessDenied: (error?: any) => Promise<boolean>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ const useDataProviderWithDeclarativeSideEffects = (): DataProviderProxy => {
['onSuccess', 'onFailure'].includes(key)
)
) {
const sideEffect = getSideEffects(resource, options);
const sideEffect = getSideEffects(
resource,
options as unknown
);
let {
onSuccess: ignoreOnSuccess, // Used to extract options without onSuccess
onFailure: ignoreOnFailure, // Used to extract options without onFailure
Expand Down
33 changes: 28 additions & 5 deletions packages/ra-core/src/dataProvider/useDeclarativeSideEffects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ import {
useRedirect,
useRefresh,
useUnselectAll,
NotificationSideEffect,
RedirectionSideEffect,
} from '../sideEffect';
import { OnSuccess, OnFailure } from '../types';
import { useMemo } from 'react';

const defaultSideEffects = {
onSuccess: undefined,
onFailure: undefined,
};
const useDeclarativeSideEffects = () => {
const notify = useNotify();
const redirect = useRedirect();
Expand All @@ -15,11 +22,11 @@ const useDeclarativeSideEffects = () => {
return useMemo(
() => (
resource,
{ onSuccess, onFailure }: any = {
onSuccess: undefined,
onFailure: undefined,
}
) => {
{
onSuccess,
onFailure,
}: DeclarativeSideEffects = defaultSideEffects
): FunctionSideEffects => {
const convertToFunctionSideEffect = (resource, sideEffects) => {
if (!sideEffects || typeof sideEffects === 'function') {
return sideEffects;
Expand Down Expand Up @@ -68,4 +75,20 @@ const useDeclarativeSideEffects = () => {
);
};

export interface DeclarativeSideEffect {
notification?: NotificationSideEffect;
redirectTo?: RedirectionSideEffect;
refresh?: boolean;
unselectAll?: boolean;
}

export interface DeclarativeSideEffects {
onSuccess?: DeclarativeSideEffect;
onFailure?: DeclarativeSideEffect;
}
export interface FunctionSideEffects {
onSuccess: OnSuccess;
onFailure: OnFailure;
}

export default useDeclarativeSideEffects;
11 changes: 6 additions & 5 deletions packages/ra-core/src/dataProvider/useMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { useCallback } from 'react';
import merge from 'lodash/merge';

import { useSafeSetState } from '../util/hooks';
import { MutationMode } from '../types';
import { MutationMode, OnSuccess, OnFailure } from '../types';
import useDataProvider from './useDataProvider';
import useDataProviderWithDeclarativeSideEffects from './useDataProviderWithDeclarativeSideEffects';
import { DeclarativeSideEffect } from './useDeclarativeSideEffects';

/**
* Get a callback to fetch the data provider through Redux, usually for mutations.
Expand Down Expand Up @@ -33,8 +34,8 @@ import useDataProviderWithDeclarativeSideEffects from './useDataProviderWithDecl
* @param {string} options.action Redux action type
* @param {boolean} options.undoable Set to true to run the mutation locally before calling the dataProvider
* @param {boolean} options.returnPromise Set to true to return the result promise of the mutation
* @param {Function} options.onSuccess Side effect function to be executed upon success or failure, e.g. { onSuccess: response => refresh() }
* @param {Function} options.onFailure Side effect function to be executed upon failure, e.g. { onFailure: error => notify(error.message) }
* @param {Function} options.onSuccess Side effect function to be executed upon success, e.g. () => refresh()
* @param {Function} options.onFailure Side effect function to be executed upon failure, e.g. (error) => notify(error.message)
* @param {boolean} options.withDeclarativeSideEffectsSupport Set to true to support legacy side effects e.g. { onSuccess: { refresh: true } }
*
* @returns A tuple with the mutation callback and the request state. Destructure as [mutate, { data, total, error, loading, loaded }].
Expand Down Expand Up @@ -220,8 +221,8 @@ export interface Mutation {
export interface MutationOptions {
action?: string;
returnPromise?: boolean;
onSuccess?: (response: any) => any | Object;
onFailure?: (error?: any) => any | Object;
onSuccess?: OnSuccess | DeclarativeSideEffect;
onFailure?: OnFailure | DeclarativeSideEffect;
withDeclarativeSideEffectsSupport?: boolean;
/** @deprecated use mutationMode: undoable instead */
undoable?: boolean;
Expand Down
10 changes: 6 additions & 4 deletions packages/ra-core/src/dataProvider/useQuery.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useEffect } from 'react';

import { useSafeSetState } from '../util/hooks';
import { OnSuccess, OnFailure } from '../types';
import useDataProvider from './useDataProvider';
import useDataProviderWithDeclarativeSideEffects from './useDataProviderWithDeclarativeSideEffects';
import { DeclarativeSideEffect } from './useDeclarativeSideEffects';
import useVersion from '../controller/useVersion';

/**
Expand All @@ -20,8 +22,8 @@ import useVersion from '../controller/useVersion';
* @param {Object} query.payload The payload object, e.g; { post_id: 12 }
* @param {Object} options
* @param {string} options.action Redux action type
* @param {Function} options.onSuccess Side effect function to be executed upon success or failure, e.g. { onSuccess: response => refresh() }
* @param {Function} options.onFailure Side effect function to be executed upon failure, e.g. { onFailure: error => notify(error.message) }
* @param {Function} options.onSuccess Side effect function to be executed upon success, e.g. () => refresh()
* @param {Function} options.onFailure Side effect function to be executed upon failure, e.g. (error) => notify(error.message)
* @param {boolean} options.withDeclarativeSideEffectsSupport Set to true to support legacy side effects e.g. { onSuccess: { refresh: true } }
*
* @returns The current request state. Destructure as { data, total, error, loading, loaded }.
Expand Down Expand Up @@ -143,8 +145,8 @@ export interface Query {

export interface QueryOptions {
action?: string;
onSuccess?: (response: any) => any | Object;
onFailure?: (error?: any) => any | Object;
onSuccess?: OnSuccess | DeclarativeSideEffect;
onFailure?: OnFailure | DeclarativeSideEffect;
withDeclarativeSideEffectsSupport?: boolean;
}

Expand Down
10 changes: 5 additions & 5 deletions packages/ra-core/src/dataProvider/useQueryWithStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import useDataProvider from './useDataProvider';
import useVersion from '../controller/useVersion';
import getFetchType from './getFetchType';
import { useSafeSetState } from '../util/hooks';
import { ReduxState } from '../types';
import { ReduxState, OnSuccess, OnFailure } from '../types';

export interface Query {
type: string;
Expand All @@ -23,8 +23,8 @@ export interface StateResult {
}

export interface QueryOptions {
onSuccess?: (args?: any) => void;
onFailure?: (error: any) => void;
onSuccess?: OnSuccess;
onFailure?: OnFailure;
action?: string;
[key: string]: any;
}
Expand Down Expand Up @@ -79,8 +79,8 @@ const defaultIsDataLoaded = (data: any): boolean => data !== undefined;
* @param {Object} query.payload The payload object, e.g; { post_id: 12 }
* @param {Object} options
* @param {string} options.action Redux action type
* @param {Function} options.onSuccess Side effect function to be executed upon success or failure, e.g. { onSuccess: response => refresh() }
* @param {Function} options.onFailure Side effect function to be executed upon failure, e.g. { onFailure: error => notify(error.message) }
* @param {Function} options.onSuccess Side effect function to be executed upon success, e.g. () => refresh()
* @param {Function} options.onFailure Side effect function to be executed upon failure, e.g. (error) => notify(error.message)
* @param {Function} dataSelector Redux selector to get the result. Required.
* @param {Function} totalSelector Redux selector to get the total (optional, only for LIST queries)
* @param {Function} isDataLoaded
Expand Down
6 changes: 3 additions & 3 deletions packages/ra-core/src/form/FormWithRedirect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import useInitializeFormWithRecord from './useInitializeFormWithRecord';
import useWarnWhenUnsavedChanges from './useWarnWhenUnsavedChanges';
import sanitizeEmptyValues from './sanitizeEmptyValues';
import getFormInitialValues from './getFormInitialValues';
import { FormContextValue, Record } from '../types';
import { FormContextValue, Record, OnSuccess, OnFailure } from '../types';
import { RedirectionSideEffect } from '../sideEffect';
import { useDispatch } from 'react-redux';
import { setAutomaticRefresh } from '../actions/uiActions';
Expand Down Expand Up @@ -192,8 +192,8 @@ export type FormWithRedirectSave = (
data: Partial<Record>,
redirectTo: RedirectionSideEffect,
options?: {
onSuccess?: (data?: any) => void;
onFailure?: (error: any) => void;
onSuccess?: OnSuccess;
onFailure?: OnFailure;
}
) => void;
export interface FormWithRedirectOwnProps {
Expand Down
5 changes: 3 additions & 2 deletions packages/ra-core/src/sideEffect/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
fetchActionsWithTotalResponse,
sanitizeFetchType,
} from '../core';
import { DeclarativeSideEffect } from '../dataProvider/useDeclarativeSideEffects';

function validateResponseFormat(
response,
Expand Down Expand Up @@ -73,8 +74,8 @@ interface ActionWithSideEffect {
meta: {
fetch: string;
resource: string;
onSuccess?: any;
onFailure?: any;
onSuccess?: DeclarativeSideEffect;
onFailure?: DeclarativeSideEffect;
};
}

Expand Down
7 changes: 4 additions & 3 deletions packages/ra-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Location, History, LocationState } from 'history';

import { WithPermissionsChildrenParams } from './auth/WithPermissions';
import { AuthActionType } from './auth/types';
import { Mutation } from './dataProvider/useMutation';

/**
* data types
Expand Down Expand Up @@ -286,6 +285,8 @@ export type DataProviderProxy = {
};

export type MutationMode = 'pessimistic' | 'optimistic' | 'undoable';
export type OnSuccess = (response?: any) => void;
export type OnFailure = (error?: any) => void;
Comment on lines +288 to +289
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably avoid any in favor of unknow. See #5834

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the benefits and shortcomings of any vs unknown. What I've read at https://stackoverflow.com/questions/51439843/unknown-vs-any tells me that there may be drawbacks for end users (like the obligation to perform type checking on an unknown value before using it).

Let's keep the two discussions separate.


export interface UseDataProviderOptions {
action?: string;
Expand All @@ -294,8 +295,8 @@ export interface UseDataProviderOptions {
// @deprecated use mode: 'undoable' instead
undoable?: boolean;
mutationMode?: MutationMode;
onSuccess?: any;
onFailure?: any;
onSuccess?: OnSuccess;
onFailure?: OnFailure;
}

export type LegacyDataProvider = (
Expand Down
6 changes: 4 additions & 2 deletions packages/ra-ui-materialui/src/form/TabbedForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
MutationMode,
Record,
RedirectionSideEffect,
OnSuccess,
OnFailure,
} from 'ra-core';
import { FormRenderProps } from 'react-final-form';
import get from 'lodash/get';
Expand Down Expand Up @@ -141,8 +143,8 @@ export interface TabbedFormProps
data: Partial<Record>,
redirectTo: RedirectionSideEffect,
options?: {
onSuccess?: (data?: any) => void;
onFailure?: (error: any) => void;
onSuccess?: OnSuccess;
onFailure?: OnFailure;
}
) => void;
submitOnEnter?: boolean;
Expand Down
Loading