V8: Reusable components in TypeScript (using branded strings) #7354
Replies: 14 comments 25 replies
-
I love this RFC and this is a proper solution to address generic component type difficulty with
How could we avoid breaking change? Ideally, I hope we can avoid changing/add |
Beta Was this translation helpful? Give feedback.
-
Actually, once all functions are converted to using So the entire feature would just be two functions, a new type type PathValue<T, P extends string> =
P extends PathWithMeta<T, infer U>
? U
: PathValueImpl<T, P>; |
Beta Was this translation helpful? Give feedback.
-
Would this be able to fit into the useFormContext model? Sounds like it would be a great fit. |
Beta Was this translation helpful? Give feedback.
-
The type arguments of function PersonFields(props: { register: UseFormRegister<Person> }) {
const { register } = props
return <div>
<input type="text" {...register('name')} />
<AddressFields<Person>
register={register}
path={of('address')}
/>
</div>
}
function OrderFields(props: { register: UseFormRegister<Order> }) {
const { register } = props
return <div>
<input type="text" {...register('item')} />
<AddressFields<Order>
register={register}
path={of('shippingAddress')}
/>
</div>
} That even works when using |
Beta Was this translation helpful? Give feedback.
-
Is it also going to work with export interface ConvertSectionProps {
form: UseFormReturn<DealDetailsType>;
}
export function ConvertSection({
form: { control, watch },
}: ConvertSectionProps) {
const currency = watch("currencyCode");
return (
<ContentBlock>
<AutoFormGrid>
<InputField
control={control}
name="convertDetails.amount"
label={`Amount (${currency})`}
/>
<InputField
control={control}
name="convertDetails.maturityYears"
label="Maturity (in years)"
/>
</AutoFormGrid>
</ContentBlock>
);
} Great proposal btw, can't wait for that to happen! |
Beta Was this translation helpful? Give feedback.
-
With some small help from https://gist.github.com/panrafal/92e11be4401aee710d8616cf2b664c0d It's fully type-safe and rather easy to use. I guess it should handle every bit of RHF as it's mostly some type magic. type NestedValues = {
foo: string
}
type Values = {
nested: NestedValues
}
function FieldsToBeNested({form}: {form: NestedForm<NestedValues>> {
const errors = form.get(form.formState.errors)
return <div><input {...register(form.path('foo'))}/>{errors.foo?.message}</div>
}
function DirectForm() {
const form = useForm<NestedValues>()
return <FieldsToBeNested form={nestedForm(form)} />
}
function ComposedForm() {
const form = useForm<Values>()
return <FieldsToBeNested form={nestedForm(form, 'nested')} />
} |
Beta Was this translation helpful? Give feedback.
-
Is there a way to get this working for more than a depth of one, either in V8 or V7? The solution provided by @panrafal works great for a nested form of one depth but doesn't work for a nested form within another nested form. |
Beta Was this translation helpful? Give feedback.
-
I don't love my current solution, but maybe it will spark some ideas? Just throwing it here in case it's helpful. https://codesandbox.io/s/react-hook-form-watch-v7-ts-forked-b84nri?file=/src/PersonForm.tsx |
Beta Was this translation helpful? Give feedback.
-
I'm a bit confused on the state of this. Is this currently possible in v7? And is it "cancelled" in v8 due to this? |
Beta Was this translation helpful? Give feedback.
-
Hi, any update on this? do we need to wait for v8 and are there any plans for v8 release? |
Beta Was this translation helpful? Give feedback.
-
What is the current status of this? This PR looks like it does some of the implementation, but it was closed in June 2022. |
Beta Was this translation helpful? Give feedback.
-
It looks like similar to what I suggested some time ago #9289 |
Beta Was this translation helpful? Give feedback.
-
Hi, I created a PR that demonstrates a Lens approach for building reusable components with TypeScript support #12284 |
Beta Was this translation helpful? Give feedback.
-
The Problem
Consider an app which has a model like this: An
Address
interface which is used by both thePerson
andOrder
interfaces.In Javascript we can easily create a generic
AddressFields
component for editing the address which can be either embedded in thePersonFields
or theOrderFields
component.In Typescript this is currently almost impossible (almost because it could be done with overloads or type assertions).
Branded strings to the rescue
In Typescript you can associate extra type information with a type using type assertions: Branded types.
We could use this technique to associate a path with the type of the form values and its resolved type. E.g.
We can then define basic functions for creating and joining such branded strings.
That would then allow us to use the same pattern which we've used in Javascript.
Required Changes
PathWithMeta
.of
andjoin
could be integrated into the functions directly.useForm
could also return a bound version ofof
which would make the type annotations obsolete.Related issues
#5055
#7413
cc @kotarella1110 @jorisre @barrymay
Beta Was this translation helpful? Give feedback.
All reactions