Skip to content

Commit a9578b8

Browse files
committed
Added react-hook-form example
1 parent 74fe768 commit a9578b8

11 files changed

Lines changed: 182 additions & 1 deletion

package-lock.json

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@
149149
"express": "^4.18.1",
150150
"react": "^18.2.0",
151151
"react-dom": "^18.2.0",
152+
"react-hook-form": "^7.44.3",
152153
"zod": "^3.17.10"
153154
}
154-
}
155+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { FieldValues, useForm } from "react-hook-form";
2+
import { Equal, Expect } from "../helpers/type-utils";
3+
4+
/**
5+
* 1. When you provide default values to useForm, the return type of getValues
6+
* gets inferred as the shape of those values.
7+
*
8+
* Investigate why this is, and what TFieldValues is being used for.
9+
*/
10+
const formWithValues = useForm({
11+
defaultValues: {
12+
firstName: "",
13+
lastName: "",
14+
},
15+
});
16+
17+
const values = formWithValues.getValues();
18+
19+
type test = Expect<
20+
Equal<typeof values, { firstName: string; lastName: string }>
21+
>;
22+
23+
/**
24+
* 2. When you don't pass a default value, the return type of getValues is
25+
* inferred as FieldValues.
26+
*
27+
* Investigate why this is, and what type FieldValues is.
28+
*/
29+
30+
const formWithoutValues = useForm();
31+
32+
const values2 = formWithoutValues.getValues();
33+
34+
type test2 = Expect<Equal<typeof values2, FieldValues>>;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { useForm } from "react-hook-form";
2+
import { Equal, Expect, ExpectExtends } from "../helpers/type-utils";
3+
4+
/**
5+
* Here, we're creating a wrapper around react-hook-form's useForm hook.
6+
*
7+
* We want to change the API slightly so that only certain methods are
8+
* exposed. We also want to make sure that defaultValues is ALWAYS
9+
* required.
10+
*/
11+
const useCustomForm = (defaultValues: any) => {
12+
const form = useForm({
13+
defaultValues: defaultValues,
14+
});
15+
16+
return {
17+
register: form.register,
18+
handleSubmit: form.handleSubmit,
19+
getValues: form.getValues,
20+
};
21+
};
22+
23+
// ---- TESTS ----
24+
25+
// @ts-expect-error defaultValues is required
26+
useCustomForm();
27+
28+
useCustomForm(
29+
// @ts-expect-error defaultValues must be an object
30+
2,
31+
);
32+
33+
const customForm = useCustomForm({
34+
firstName: "",
35+
lastName: "",
36+
});
37+
38+
customForm.handleSubmit((values) => {
39+
type test = Expect<
40+
// Expect that inside handleSubmit, it's inferred as
41+
// { firstName: string; lastName: string }
42+
ExpectExtends<
43+
{
44+
firstName: string;
45+
lastName: string;
46+
},
47+
typeof values
48+
>
49+
>;
50+
});
51+
52+
// Expect that only the methods we want are exposed
53+
type test = Expect<
54+
Equal<keyof typeof customForm, "register" | "handleSubmit" | "getValues">
55+
>;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { DefaultValues, FieldValues, useForm } from "react-hook-form";
2+
import { Equal, Expect, ExpectExtends } from "../helpers/type-utils";
3+
4+
/**
5+
* We add TValues as a generic to our hook, and use it to type the defaultValues.
6+
*
7+
* We constrain it to FieldValues so that it's assignable to useForm's defaultValues.
8+
*/
9+
const useCustomForm = <TValues extends FieldValues>(defaultValues: TValues) => {
10+
const form = useForm({
11+
/**
12+
* There's a strange papercut here where we have to cast defaultValues as
13+
* DefaultValues<TValues> to get it to work.
14+
*/
15+
defaultValues: defaultValues as DefaultValues<TValues>,
16+
});
17+
18+
return {
19+
register: form.register,
20+
handleSubmit: form.handleSubmit,
21+
getValues: form.getValues,
22+
};
23+
};
24+
25+
// ---- TESTS ----
26+
27+
// @ts-expect-error defaultValues is required
28+
useCustomForm();
29+
30+
useCustomForm(
31+
// @ts-expect-error defaultValues must be an object
32+
2,
33+
);
34+
35+
const customForm = useCustomForm({
36+
firstName: "",
37+
lastName: "",
38+
});
39+
40+
customForm.handleSubmit((values) => {
41+
type test = Expect<
42+
// Expect that inside handleSubmit, it's inferred as
43+
// { firstName: string; lastName: string }
44+
ExpectExtends<
45+
{
46+
firstName: string;
47+
lastName: string;
48+
},
49+
typeof values
50+
>
51+
>;
52+
});
53+
54+
// Expect that only the methods we want are exposed
55+
type test = Expect<
56+
Equal<keyof typeof customForm, "register" | "handleSubmit" | "getValues">
57+
>;

src/08-external-libraries/59-react-hook-form.problem.tsx renamed to src/08-external-libraries/61-react-query.problem.tsx

File renamed without changes.
File renamed without changes.

src/08-external-libraries/61-redux-toolkit.problem.tsx renamed to src/08-external-libraries/63-react-select.problem.tsx

File renamed without changes.
File renamed without changes.

src/08-external-libraries/63-reusable-form-library-with-zod.problem.tsx renamed to src/08-external-libraries/65-reusable-form-library-with-zod.problem.tsx

File renamed without changes.

0 commit comments

Comments
 (0)