Skip to content

Commit

Permalink
🔧 fix data param in handleSubmit when TTransformedValues is a union t…
Browse files Browse the repository at this point in the history
…ype (#11420)

* Rewritten UseFormHandleSubmit to use default values in generics

* Updated api-extractor report

---------

Co-authored-by: Beier (Bill) <bluebill1049@hotmail.com>
  • Loading branch information
Ar4ys and bluebill1049 committed Jan 22, 2024
1 parent 919c578 commit 6fee03c
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 27 deletions.
18 changes: 9 additions & 9 deletions reports/api-extractor.md
Expand Up @@ -37,7 +37,7 @@ export type ChangeHandler = (event: {
}) => Promise<void | boolean>;

// @public (undocumented)
export type Control<TFieldValues extends FieldValues = FieldValues, TContext = any> = {
export type Control<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues extends FieldValues = TFieldValues> = {
_subjects: Subjects<TFieldValues>;
_removeUnmounted: Noop;
_names: Names;
Expand Down Expand Up @@ -76,7 +76,7 @@ export type Control<TFieldValues extends FieldValues = FieldValues, TContext = a
errors: FieldErrors;
}>;
register: UseFormRegister<TFieldValues>;
handleSubmit: UseFormHandleSubmit<TFieldValues>;
handleSubmit: UseFormHandleSubmit<TFieldValues, TTransformedValues>;
_disableForm: (disabled?: boolean) => void;
unregister: UseFormUnregister<TFieldValues>;
getFieldState: UseFormGetFieldState<TFieldValues>;
Expand Down Expand Up @@ -286,10 +286,10 @@ export type FormProps<TFieldValues extends FieldValues, TTransformedValues exten
}>;

// @public
export const FormProvider: <TFieldValues extends FieldValues, TContext = any, TTransformedValues extends FieldValues | undefined = undefined>(props: FormProviderProps<TFieldValues, TContext, TTransformedValues>) => React_2.JSX.Element;
export const FormProvider: <TFieldValues extends FieldValues, TContext = any, TTransformedValues extends FieldValues = TFieldValues>(props: FormProviderProps<TFieldValues, TContext, TTransformedValues>) => React_2.JSX.Element;

// @public (undocumented)
export type FormProviderProps<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues extends FieldValues | undefined = undefined> = {
export type FormProviderProps<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues extends FieldValues = TFieldValues> = {
children: React_2.ReactNode | React_2.ReactNode[];
} & UseFormReturn<TFieldValues, TContext, TTransformedValues>;

Expand Down Expand Up @@ -650,13 +650,13 @@ export type UseFieldArraySwap = (indexA: number, indexB: number) => void;
export type UseFieldArrayUpdate<TFieldValues extends FieldValues, TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>> = (index: number, value: FieldArray<TFieldValues, TFieldArrayName>) => void;

// @public
export function useForm<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues extends FieldValues | undefined = undefined>(props?: UseFormProps<TFieldValues, TContext>): UseFormReturn<TFieldValues, TContext, TTransformedValues>;
export function useForm<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues extends FieldValues = TFieldValues>(props?: UseFormProps<TFieldValues, TContext>): UseFormReturn<TFieldValues, TContext, TTransformedValues>;

// @public
export type UseFormClearErrors<TFieldValues extends FieldValues> = (name?: FieldPath<TFieldValues> | FieldPath<TFieldValues>[] | readonly FieldPath<TFieldValues>[] | `root.${string}` | 'root') => void;

// @public
export const useFormContext: <TFieldValues extends FieldValues, TContext = any, TransformedValues extends FieldValues | undefined = undefined>() => UseFormReturn<TFieldValues, TContext, TransformedValues>;
export const useFormContext: <TFieldValues extends FieldValues, TContext = any, TransformedValues extends FieldValues = TFieldValues>() => UseFormReturn<TFieldValues, TContext, TransformedValues>;

// @public
export type UseFormGetFieldState<TFieldValues extends FieldValues> = <TFieldName extends FieldPath<TFieldValues>>(name: TFieldName, formState?: FormState<TFieldValues>) => {
Expand All @@ -674,7 +674,7 @@ export type UseFormGetValues<TFieldValues extends FieldValues> = {
};

// @public
export type UseFormHandleSubmit<TFieldValues extends FieldValues, TTransformedValues extends FieldValues | undefined = undefined> = (onValid: TTransformedValues extends undefined ? SubmitHandler<TFieldValues> : TTransformedValues extends FieldValues ? SubmitHandler<TTransformedValues> : never, onInvalid?: SubmitErrorHandler<TFieldValues>) => (e?: React_2.BaseSyntheticEvent) => Promise<void>;
export type UseFormHandleSubmit<TFieldValues extends FieldValues, TTransformedValues extends FieldValues = TFieldValues> = (onValid: SubmitHandler<TTransformedValues>, onInvalid?: SubmitErrorHandler<TFieldValues>) => (e?: React_2.BaseSyntheticEvent) => Promise<void>;

// @public (undocumented)
export type UseFormProps<TFieldValues extends FieldValues = FieldValues, TContext = any> = Partial<{
Expand Down Expand Up @@ -727,7 +727,7 @@ export type UseFormResetField<TFieldValues extends FieldValues> = <TFieldName ex
}>) => void;

// @public (undocumented)
export type UseFormReturn<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues extends FieldValues | undefined = undefined> = {
export type UseFormReturn<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues extends FieldValues = TFieldValues> = {
watch: UseFormWatch<TFieldValues>;
getValues: UseFormGetValues<TFieldValues>;
getFieldState: UseFormGetFieldState<TFieldValues>;
Expand All @@ -740,7 +740,7 @@ export type UseFormReturn<TFieldValues extends FieldValues = FieldValues, TConte
reset: UseFormReset<TFieldValues>;
handleSubmit: UseFormHandleSubmit<TFieldValues, TTransformedValues>;
unregister: UseFormUnregister<TFieldValues>;
control: Control<TFieldValues, TContext>;
control: Control<TFieldValues, TContext, TTransformedValues>;
register: UseFormRegister<TFieldValues>;
setFocus: UseFormSetFocus<TFieldValues>;
};
Expand Down
17 changes: 17 additions & 0 deletions src/__typetest__/form.test-d.ts
Expand Up @@ -25,6 +25,23 @@ import { useForm } from '../useForm';

handleSubmit((data) => expectType<{ test: string; test1: number }>(data));
}

/** it should infer the correct TTransformedValues from useForm generic */ {
/* eslint-disable react-hooks/rules-of-hooks */
const { handleSubmit } = useForm<
{ test: string },
unknown,
{ test: string } | { test1: number }
>();

handleSubmit((data) => {
// @ts-expect-error `data` should be union and thus should not be assignable to `{ test: string }`
expectType<{ test: string }>(data);
// @ts-expect-error `data` should be union and thus should not be assignable to `{ test1: number }`
expectType<{ test1: number }>(data);
expectType<{ test: string } | { test1: number }>(data);
});
}
}

/** {@link UseFormGetFieldState} */ {
Expand Down
10 changes: 7 additions & 3 deletions src/logic/createFormControl.ts
Expand Up @@ -93,10 +93,14 @@ const defaultOptions = {
export function createFormControl<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues extends FieldValues = TFieldValues,
>(
props: UseFormProps<TFieldValues, TContext> = {},
flushRootRender: () => void,
): Omit<UseFormReturn<TFieldValues, TContext>, 'formState'> {
): Omit<
UseFormReturn<TFieldValues, TContext, TTransformedValues>,
'formState'
> {
let _options = {
...defaultOptions,
...props,
Expand Down Expand Up @@ -1096,7 +1100,7 @@ export function createFormControl<
}
};

const handleSubmit: UseFormHandleSubmit<TFieldValues> =
const handleSubmit: UseFormHandleSubmit<TFieldValues, TTransformedValues> =
(onValid, onInvalid) => async (e) => {
let onValidError = undefined;
if (e) {
Expand Down Expand Up @@ -1124,7 +1128,7 @@ export function createFormControl<
errors: {},
});
try {
await onValid(fieldValues as TFieldValues, e);
await onValid(fieldValues as TFieldValues & TTransformedValues, e);
} catch (error) {
onValidError = error;
}
Expand Down
8 changes: 6 additions & 2 deletions src/logic/getProxyFormState.ts
@@ -1,9 +1,13 @@
import { VALIDATION_MODE } from '../constants';
import { Control, FieldValues, FormState, ReadFormState } from '../types';

export default <TFieldValues extends FieldValues, TContext = any>(
export default <
TFieldValues extends FieldValues,
TContext = any,
TTransformedValues extends FieldValues = TFieldValues,
>(
formState: FormState<TFieldValues>,
control: Control<TFieldValues, TContext>,
control: Control<TFieldValues, TContext, TTransformedValues>,
localProxyFormState?: ReadFormState,
isRoot = true,
) => {
Expand Down
17 changes: 7 additions & 10 deletions src/types/form.ts
Expand Up @@ -627,13 +627,9 @@ export type UseFormUnregister<TFieldValues extends FieldValues> = (
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type UseFormHandleSubmit<
TFieldValues extends FieldValues,
TTransformedValues extends FieldValues | undefined = undefined,
TTransformedValues extends FieldValues = TFieldValues,
> = (
onValid: TTransformedValues extends undefined
? SubmitHandler<TFieldValues>
: TTransformedValues extends FieldValues
? SubmitHandler<TTransformedValues>
: never,
onValid: SubmitHandler<TTransformedValues>,
onInvalid?: SubmitErrorHandler<TFieldValues>,
) => (e?: React.BaseSyntheticEvent) => Promise<void>;

Expand Down Expand Up @@ -769,6 +765,7 @@ export type BatchFieldArrayUpdate = <
export type Control<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues extends FieldValues = TFieldValues,
> = {
_subjects: Subjects<TFieldValues>;
_removeUnmounted: Noop;
Expand Down Expand Up @@ -815,7 +812,7 @@ export type Control<
names: InternalFieldName[],
) => Promise<{ errors: FieldErrors }>;
register: UseFormRegister<TFieldValues>;
handleSubmit: UseFormHandleSubmit<TFieldValues>;
handleSubmit: UseFormHandleSubmit<TFieldValues, TTransformedValues>;
_disableForm: (disabled?: boolean) => void;
unregister: UseFormUnregister<TFieldValues>;
getFieldState: UseFormGetFieldState<TFieldValues>;
Expand All @@ -833,7 +830,7 @@ export type WatchObserver<TFieldValues extends FieldValues> = (
export type UseFormReturn<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues extends FieldValues | undefined = undefined,
TTransformedValues extends FieldValues = TFieldValues,
> = {
watch: UseFormWatch<TFieldValues>;
getValues: UseFormGetValues<TFieldValues>;
Expand All @@ -847,7 +844,7 @@ export type UseFormReturn<
reset: UseFormReset<TFieldValues>;
handleSubmit: UseFormHandleSubmit<TFieldValues, TTransformedValues>;
unregister: UseFormUnregister<TFieldValues>;
control: Control<TFieldValues, TContext>;
control: Control<TFieldValues, TContext, TTransformedValues>;
register: UseFormRegister<TFieldValues>;
setFocus: UseFormSetFocus<TFieldValues>;
};
Expand Down Expand Up @@ -879,7 +876,7 @@ export type UseWatchProps<TFieldValues extends FieldValues = FieldValues> = {
export type FormProviderProps<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues extends FieldValues | undefined = undefined,
TTransformedValues extends FieldValues = TFieldValues,
> = {
children: React.ReactNode | React.ReactNode[];
} & UseFormReturn<TFieldValues, TContext, TTransformedValues>;
Expand Down
2 changes: 1 addition & 1 deletion src/useForm.ts
Expand Up @@ -46,7 +46,7 @@ import { useSubscribe } from './useSubscribe';
export function useForm<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
TTransformedValues extends FieldValues | undefined = undefined,
TTransformedValues extends FieldValues = TFieldValues,
>(
props: UseFormProps<TFieldValues, TContext> = {},
): UseFormReturn<TFieldValues, TContext, TTransformedValues> {
Expand Down
4 changes: 2 additions & 2 deletions src/useFormContext.tsx
Expand Up @@ -37,7 +37,7 @@ const HookFormContext = React.createContext<UseFormReturn | null>(null);
export const useFormContext = <
TFieldValues extends FieldValues,
TContext = any,
TransformedValues extends FieldValues | undefined = undefined,
TransformedValues extends FieldValues = TFieldValues,
>(): UseFormReturn<TFieldValues, TContext, TransformedValues> =>
React.useContext(HookFormContext) as UseFormReturn<
TFieldValues,
Expand Down Expand Up @@ -78,7 +78,7 @@ export const useFormContext = <
export const FormProvider = <
TFieldValues extends FieldValues,
TContext = any,
TTransformedValues extends FieldValues | undefined = undefined,
TTransformedValues extends FieldValues = TFieldValues,
>(
props: FormProviderProps<TFieldValues, TContext, TTransformedValues>,
) => {
Expand Down

0 comments on commit 6fee03c

Please sign in to comment.