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

Fix data param in handleSubmit when TTransformedValues is a union type #11420

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Despite adding new generic to Control, this should not be a breaking change, because TTransformedValues has a default value of TFieldValues, so previous code that only specified TFieldValues should still work as expected.

Copy link
Member

Choose a reason for hiding this comment

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

nice 👍

> = {
_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