From 7746921c8abfd683f0d79e2ce95f9e827bd4d6b2 Mon Sep 17 00:00:00 2001 From: Sullivan SENECHAL Date: Mon, 16 May 2022 21:18:33 +0200 Subject: [PATCH] feat(hooks): mutation error typing --- docs/useCreate.md | 14 +++++++++ docs/useDelete.md | 14 +++++++++ docs/useDeleteMany.md | 14 +++++++++ docs/useUpdate.md | 14 +++++++++ docs/useUpdateMany.md | 14 +++++++++ .../controller/create/useCreateController.ts | 23 ++++++++------ .../src/controller/edit/useEditController.ts | 23 ++++++++------ .../ra-core/src/dataProvider/useCreate.ts | 25 +++++++++------ .../ra-core/src/dataProvider/useDelete.ts | 31 ++++++++++++------- .../ra-core/src/dataProvider/useDeleteMany.ts | 29 ++++++++++------- .../ra-core/src/dataProvider/useUpdate.ts | 27 +++++++++------- .../ra-core/src/dataProvider/useUpdateMany.ts | 29 ++++++++++------- packages/ra-ui-materialui/src/types.ts | 14 ++++++--- 13 files changed, 194 insertions(+), 77 deletions(-) diff --git a/docs/useCreate.md b/docs/useCreate.md index deda552b18c..b473a6f63b0 100644 --- a/docs/useCreate.md +++ b/docs/useCreate.md @@ -55,3 +55,17 @@ const LikeButton = ({ record }) => { return ; }; ``` + +**Tip**: If you use TypeScript, you can specify the record and error types for more type safety: + +```tsx +useCreate(undefined, undefined, { + onError: (error) => { + // error is an instance of Error. + }, + onSettled: (data, error) => { + // data is an instance of Product. + // error is an instance of Error. + }, +}) +``` diff --git a/docs/useDelete.md b/docs/useDelete.md index 2765291534d..e271571abe9 100644 --- a/docs/useDelete.md +++ b/docs/useDelete.md @@ -59,3 +59,17 @@ const DeleteButton = ({ record }) => { return ; }; ``` + +**Tip**: If you use TypeScript, you can specify the record and error types for more type safety: + +```tsx +useDelete(undefined, undefined, { + onError: (error) => { + // error is an instance of Error. + }, + onSettled: (data, error) => { + // data is an instance of Product. + // error is an instance of Error. + }, +}) +``` diff --git a/docs/useDeleteMany.md b/docs/useDeleteMany.md index 2b192b272ab..7cbf0c82f2d 100644 --- a/docs/useDeleteMany.md +++ b/docs/useDeleteMany.md @@ -59,3 +59,17 @@ const BulkDeletePostsButton = ({ selectedIds }) => { return ; }; ``` + +**Tip**: If you use TypeScript, you can specify the record and error types for more type safety: + +```tsx +useDeleteMany(undefined, undefined, { + onError: (error) => { + // error is an instance of Error. + }, + onSettled: (data, error) => { + // data is an instance of Product. + // error is an instance of Error. + }, +}) +``` diff --git a/docs/useUpdate.md b/docs/useUpdate.md index 7c48643b14a..1b045413e8f 100644 --- a/docs/useUpdate.md +++ b/docs/useUpdate.md @@ -61,3 +61,17 @@ const IncreaseLikeButton = ({ record }) => { return ; }; ``` + +**Tip**: If you use TypeScript, you can specify the record and error types for more type safety: + +```tsx +useUpdate(undefined, undefined, { + onError: (error) => { + // error is an instance of Error. + }, + onSettled: (data, error) => { + // data is an instance of Product. + // error is an instance of Error. + }, +}) +``` diff --git a/docs/useUpdateMany.md b/docs/useUpdateMany.md index bf526149065..80330a737a5 100644 --- a/docs/useUpdateMany.md +++ b/docs/useUpdateMany.md @@ -60,3 +60,17 @@ const BulkResetViewsButton = ({ selectedIds }) => { return ; }; ``` + +**Tip**: If you use TypeScript, you can specify the record and error types for more type safety: + +```tsx +useUpdateMany(undefined, undefined, { + onError: (error) => { + // error is an instance of Error. + }, + onSettled: (data, error) => { + // data is an instance of Product. + // error is an instance of Error. + }, +}) +``` diff --git a/packages/ra-core/src/controller/create/useCreateController.ts b/packages/ra-core/src/controller/create/useCreateController.ts index b49258bd40f..f0e0b45a353 100644 --- a/packages/ra-core/src/controller/create/useCreateController.ts +++ b/packages/ra-core/src/controller/create/useCreateController.ts @@ -35,8 +35,11 @@ import { * return ; * } */ -export const useCreateController = ( - props: CreateControllerProps = {} +export const useCreateController = < + RecordType extends RaRecord = RaRecord, + MutationOptionsError = unknown +>( + props: CreateControllerProps = {} ): CreateControllerResult => { const { disableAuthentication, @@ -63,11 +66,10 @@ export const useCreateController = ( unregisterMutationMiddleware, } = useMutationMiddlewares(); - const [create, { isLoading: saving }] = useCreate( - resource, - undefined, - otherMutationOptions - ); + const [create, { isLoading: saving }] = useCreate< + RecordType, + MutationOptionsError + >(resource, undefined, otherMutationOptions); const save = useCallback( ( @@ -166,7 +168,10 @@ export const useCreateController = ( }; }; -export interface CreateControllerProps { +export interface CreateControllerProps< + RecordType extends RaRecord = RaRecord, + MutationOptionsError = unknown +> { disableAuthentication?: boolean; hasEdit?: boolean; hasShow?: boolean; @@ -175,7 +180,7 @@ export interface CreateControllerProps { resource?: string; mutationOptions?: UseMutationOptions< RecordType, - unknown, + MutationOptionsError, UseCreateMutateParams >; transform?: TransformData; diff --git a/packages/ra-core/src/controller/edit/useEditController.ts b/packages/ra-core/src/controller/edit/useEditController.ts index a96fba3ff3d..014063930cc 100644 --- a/packages/ra-core/src/controller/edit/useEditController.ts +++ b/packages/ra-core/src/controller/edit/useEditController.ts @@ -39,8 +39,11 @@ import { SaveContextValue, useMutationMiddlewares } from '../saveContext'; * return ; * } */ -export const useEditController = ( - props: EditControllerProps = {} +export const useEditController = < + RecordType extends RaRecord = any, + MutationOptionsError = unknown +>( + props: EditControllerProps = {} ): EditControllerResult => { const { disableAuthentication, @@ -101,11 +104,10 @@ export const useEditController = ( const recordCached = { id, previousData: record }; - const [update, { isLoading: saving }] = useUpdate( - resource, - recordCached, - { ...otherMutationOptions, mutationMode } - ); + const [update, { isLoading: saving }] = useUpdate< + RecordType, + MutationOptionsError + >(resource, recordCached, { ...otherMutationOptions, mutationMode }); const save = useCallback( ( @@ -211,13 +213,16 @@ export const useEditController = ( }; }; -export interface EditControllerProps { +export interface EditControllerProps< + RecordType extends RaRecord = any, + MutationOptionsError = unknown +> { disableAuthentication?: boolean; id?: RecordType['id']; mutationMode?: MutationMode; mutationOptions?: UseMutationOptions< RecordType, - unknown, + MutationOptionsError, UseUpdateMutateParams >; queryOptions?: UseQueryOptions; diff --git a/packages/ra-core/src/dataProvider/useCreate.ts b/packages/ra-core/src/dataProvider/useCreate.ts index 47dd9742161..73d7027834f 100644 --- a/packages/ra-core/src/dataProvider/useCreate.ts +++ b/packages/ra-core/src/dataProvider/useCreate.ts @@ -66,11 +66,14 @@ import { RaRecord, CreateParams } from '../types'; * const [create, { data }] = useCreate('products', { data: product }); * \-- data is Product */ -export const useCreate = ( +export const useCreate = < + RecordType extends RaRecord = any, + MutationError = unknown +>( resource?: string, params: Partial>> = {}, - options: UseCreateOptions = {} -): UseCreateResult => { + options: UseCreateOptions = {} +): UseCreateResult => { const dataProvider = useDataProvider(); const queryClient = useQueryClient(); const paramsRef = useRef>>>( @@ -79,7 +82,7 @@ export const useCreate = ( const mutation = useMutation< RecordType, - unknown, + MutationError, Partial> >( ({ @@ -119,7 +122,7 @@ export const useCreate = ( callTimeParams: Partial> = {}, createOptions: MutateOptions< RecordType, - unknown, + MutationError, Partial>, unknown > & { returnPromise?: boolean } = {} @@ -147,30 +150,32 @@ export interface UseCreateMutateParams { } export type UseCreateOptions< - RecordType extends RaRecord = any + RecordType extends RaRecord = any, + MutationError = unknown > = UseMutationOptions< RecordType, - unknown, + MutationError, Partial> >; export type UseCreateResult< RecordType extends RaRecord = any, - TReturnPromise extends boolean = boolean + TReturnPromise extends boolean = boolean, + MutationError = unknown > = [ ( resource?: string, params?: Partial>>, options?: MutateOptions< RecordType, - unknown, + MutationError, Partial>, unknown > & { returnPromise?: TReturnPromise } ) => Promise, UseMutationResult< RecordType, - unknown, + MutationError, Partial>, unknown > diff --git a/packages/ra-core/src/dataProvider/useDelete.ts b/packages/ra-core/src/dataProvider/useDelete.ts index 68b1701abaa..5ed5a81989d 100644 --- a/packages/ra-core/src/dataProvider/useDelete.ts +++ b/packages/ra-core/src/dataProvider/useDelete.ts @@ -68,11 +68,14 @@ import { RaRecord, DeleteParams, MutationMode } from '../types'; * const [delete, { data }] = useDelete('products', { id, previousData: product }); * \-- data is Product */ -export const useDelete = ( +export const useDelete = < + RecordType extends RaRecord = any, + MutationError = unknown +>( resource?: string, params: Partial> = {}, - options: UseDeleteOptions = {} -): UseDeleteResult => { + options: UseDeleteOptions = {} +): UseDeleteResult => { const dataProvider = useDataProvider(); const queryClient = useQueryClient(); const { id, previousData } = params; @@ -141,7 +144,7 @@ export const useDelete = ( const mutation = useMutation< RecordType, - unknown, + MutationError, Partial> >( ({ @@ -176,7 +179,7 @@ export const useDelete = ( } }, onError: ( - error: unknown, + error: MutationError, variables: Partial> = {}, context: { snapshot: Snapshot } ) => { @@ -227,7 +230,7 @@ export const useDelete = ( }, onSettled: ( data: RecordType, - error: unknown, + error: MutationError, variables: Partial> = {}, context: { snapshot: Snapshot } ) => { @@ -258,7 +261,7 @@ export const useDelete = ( callTimeParams: Partial> = {}, updateOptions: MutateOptions< RecordType, - unknown, + MutationError, Partial>, unknown > & { mutationMode?: MutationMode } = {} @@ -388,27 +391,31 @@ export interface UseDeleteMutateParams { } export type UseDeleteOptions< - RecordType extends RaRecord = any + RecordType extends RaRecord = any, + MutationError = unknown > = UseMutationOptions< RecordType, - unknown, + MutationError, Partial> > & { mutationMode?: MutationMode }; -export type UseDeleteResult = [ +export type UseDeleteResult< + RecordType extends RaRecord = any, + MutationError = unknown +> = [ ( resource?: string, params?: Partial>, options?: MutateOptions< RecordType, - unknown, + MutationError, Partial>, unknown > & { mutationMode?: MutationMode } ) => Promise, UseMutationResult< RecordType, - unknown, + MutationError, Partial & { resource?: string }>, unknown > diff --git a/packages/ra-core/src/dataProvider/useDeleteMany.ts b/packages/ra-core/src/dataProvider/useDeleteMany.ts index c09aa2ccf79..a7f3f0e4f88 100644 --- a/packages/ra-core/src/dataProvider/useDeleteMany.ts +++ b/packages/ra-core/src/dataProvider/useDeleteMany.ts @@ -70,11 +70,14 @@ import { RaRecord, DeleteManyParams, MutationMode } from '../types'; * const [deleteMany, { data }] = useDeleteMany('products', { ids }); * \-- data is Product */ -export const useDeleteMany = ( +export const useDeleteMany = < + RecordType extends RaRecord = any, + MutationError = unknown +>( resource?: string, params: Partial> = {}, - options: UseDeleteManyOptions = {} -): UseDeleteManyResult => { + options: UseDeleteManyOptions = {} +): UseDeleteManyResult => { const dataProvider = useDataProvider(); const queryClient = useQueryClient(); const { ids } = params; @@ -154,7 +157,7 @@ export const useDeleteMany = ( const mutation = useMutation< RecordType['id'][], - unknown, + MutationError, Partial> >( ({ @@ -187,7 +190,7 @@ export const useDeleteMany = ( } }, onError: ( - error: unknown, + error: MutationError, variables: Partial> = {}, context: { snapshot: Snapshot } ) => { @@ -238,7 +241,7 @@ export const useDeleteMany = ( }, onSettled: ( data: RecordType['id'][], - error: unknown, + error: MutationError, variables: Partial> = {}, context: { snapshot: Snapshot } ) => { @@ -394,27 +397,31 @@ export interface UseDeleteManyMutateParams { } export type UseDeleteManyOptions< - RecordType extends RaRecord = any + RecordType extends RaRecord = any, + MutationError = unknown > = UseMutationOptions< RecordType['id'][], - unknown, + MutationError, Partial> > & { mutationMode?: MutationMode }; -export type UseDeleteManyResult = [ +export type UseDeleteManyResult< + RecordType extends RaRecord = any, + MutationError = unknown +> = [ ( resource?: string, params?: Partial>, options?: MutateOptions< RecordType['id'][], - unknown, + MutationError, Partial>, unknown > & { mutationMode?: MutationMode } ) => Promise, UseMutationResult< RecordType['id'][], - unknown, + MutationError, Partial & { resource?: string }>, unknown > diff --git a/packages/ra-core/src/dataProvider/useUpdate.ts b/packages/ra-core/src/dataProvider/useUpdate.ts index 3ea10d87daa..0fc872cbbb2 100644 --- a/packages/ra-core/src/dataProvider/useUpdate.ts +++ b/packages/ra-core/src/dataProvider/useUpdate.ts @@ -72,11 +72,14 @@ import { RaRecord, UpdateParams, MutationMode } from '../types'; * const [update, { data }] = useUpdate('products', { id, data: diff, previousData: product }); * \-- data is Product */ -export const useUpdate = ( +export const useUpdate = < + RecordType extends RaRecord = any, + MutationError = unknown +>( resource?: string, params: Partial> = {}, - options: UseUpdateOptions = {} -): UseUpdateResult => { + options: UseUpdateOptions = {} +): UseUpdateResult => { const dataProvider = useDataProvider(); const queryClient = useQueryClient(); const { id, data, meta } = params; @@ -140,7 +143,7 @@ export const useUpdate = ( const mutation = useMutation< RecordType, - unknown, + MutationError, Partial> >( ({ @@ -177,7 +180,7 @@ export const useUpdate = ( } }, onError: ( - error: unknown, + error: MutationError, variables: Partial> = {}, context: { snapshot: Snapshot } ) => { @@ -229,7 +232,7 @@ export const useUpdate = ( }, onSettled: ( data: RecordType, - error: unknown, + error: MutationError, variables: Partial> = {}, context: { snapshot: Snapshot } ) => { @@ -422,30 +425,32 @@ export interface UseUpdateMutateParams { } export type UseUpdateOptions< - RecordType extends RaRecord = any + RecordType extends RaRecord = any, + MutationError = unknown > = UseMutationOptions< RecordType, - unknown, + MutationError, Partial> > & { mutationMode?: MutationMode }; export type UseUpdateResult< RecordType extends RaRecord = any, - TReturnPromise extends boolean = boolean + TReturnPromise extends boolean = boolean, + MutationError = unknown > = [ ( resource?: string, params?: Partial>, options?: MutateOptions< RecordType, - unknown, + MutationError, Partial>, unknown > & { mutationMode?: MutationMode; returnPromise?: TReturnPromise } ) => Promise, UseMutationResult< RecordType, - unknown, + MutationError, Partial & { resource?: string }>, unknown > diff --git a/packages/ra-core/src/dataProvider/useUpdateMany.ts b/packages/ra-core/src/dataProvider/useUpdateMany.ts index d40b74a15b0..fd7296fff97 100644 --- a/packages/ra-core/src/dataProvider/useUpdateMany.ts +++ b/packages/ra-core/src/dataProvider/useUpdateMany.ts @@ -66,11 +66,14 @@ import { Identifier } from '..'; * return ; * }; */ -export const useUpdateMany = ( +export const useUpdateMany = < + RecordType extends RaRecord = any, + MutationError = unknown +>( resource?: string, params: Partial>> = {}, - options: UseUpdateManyOptions = {} -): UseUpdateManyResult => { + options: UseUpdateManyOptions = {} +): UseUpdateManyResult => { const dataProvider = useDataProvider(); const queryClient = useQueryClient(); const { ids, data, meta } = params; @@ -150,7 +153,7 @@ export const useUpdateMany = ( const mutation = useMutation< Array, - unknown, + MutationError, Partial> >( ({ @@ -185,7 +188,7 @@ export const useUpdateMany = ( } }, onError: ( - error: unknown, + error: MutationError, variables: Partial> = {}, context: { snapshot: Snapshot } ) => { @@ -239,7 +242,7 @@ export const useUpdateMany = ( }, onSettled: ( data: Array, - error: unknown, + error: MutationError, variables: Partial> = {}, context: { snapshot: Snapshot } ) => { @@ -405,27 +408,31 @@ export interface UseUpdateManyMutateParams { } export type UseUpdateManyOptions< - RecordType extends RaRecord = any + RecordType extends RaRecord = any, + MutationError = unknown > = UseMutationOptions< Array, - unknown, + MutationError, Partial> > & { mutationMode?: MutationMode }; -export type UseUpdateManyResult = [ +export type UseUpdateManyResult< + RecordType extends RaRecord = any, + MutationError = unknown +> = [ ( resource?: string, params?: Partial>, options?: MutateOptions< Array, - unknown, + MutationError, Partial>, unknown > & { mutationMode?: MutationMode } ) => Promise, UseMutationResult< Array, - unknown, + MutationError, Partial> & { resource?: string }>, unknown > diff --git a/packages/ra-ui-materialui/src/types.ts b/packages/ra-ui-materialui/src/types.ts index 2a7c92f750c..4bea539f15c 100644 --- a/packages/ra-ui-materialui/src/types.ts +++ b/packages/ra-ui-materialui/src/types.ts @@ -11,7 +11,10 @@ import { } from 'ra-core'; import { UseQueryOptions, UseMutationOptions } from 'react-query'; -export interface EditProps { +export interface EditProps< + RecordType extends RaRecord = any, + MutationOptionsError = unknown +> { actions?: ReactElement | false; aside?: ReactElement; className?: string; @@ -22,7 +25,7 @@ export interface EditProps { queryOptions?: UseQueryOptions; mutationOptions?: UseMutationOptions< RecordType, - unknown, + MutationOptionsError, UseUpdateMutateParams >; redirect?: RedirectionSideEffect; @@ -32,7 +35,10 @@ export interface EditProps { sx?: SxProps; } -export interface CreateProps { +export interface CreateProps< + RecordType extends RaRecord = any, + MutationOptionsError = unknown +> { actions?: ReactElement | false; aside?: ReactElement; className?: string; @@ -45,7 +51,7 @@ export interface CreateProps { resource?: string; mutationOptions?: UseMutationOptions< RecordType, - unknown, + MutationOptionsError, UseCreateMutateParams >; transform?: TransformData;