Replies: 3 comments 4 replies
-
Would love any pointers how to solve this :) Sorry if this has been asked already somewhere! |
Beta Was this translation helpful? Give feedback.
-
Hi there. I'm also tackling this problem at the moment. For your exact example, I came up with this solution which seems to accomplish what you would want. import { FormApi, useField, DeepKeys, useForm } from "@tanstack/react-form";
import React from "react";
type TDataFromForm<Form extends FormApi<any>> = Form extends FormApi<infer Data> ? Data : never;
type TTextFieldProps<Form extends FormApi<any>> = {
form: Form;
name: DeepKeys<TDataFromForm<Form>>;
label?: string;
};
type TTextField = <Form extends FormApi<any>>(props: TTextFieldProps<Form>) => React.ReactElement;
export const TextField: TTextField = ({ name, label, form }) => {
const { getValue, handleBlur, handleChange, getMeta } = useField({
form,
name
})
return (
<div>
{label && <label htmlFor={name}>{label}</label>}
<input
value={getValue()}
name={name}
onChange={(e) => handleChange(e.target.value as any)}
onBlur={handleBlur}
/>
<div>{getMeta().touchedErrors?.join(", ")}</div>
</div>
);
}; I've replaced your specific components with divs just for examples sake. From my understanding, this is working because it's essentially creating a new, unrelated form field using the useField hook, so the types are not in conflict. This would still indicate that there is some type errors going on but for all intensive purposes, this works and will not give type errors while still giving intellisense for the name field. Now where the problem comes in. This has horrible typescript performance. To the point where if you write any code that is invalid, it will spontanously take 30 seconds to work out the type error and honestly just sometimes crashes for me. I wanted to take this abstraction a bit further in my case so that I didn't need to pass the form to each of my fields, so my solution to that was having a generator function (hook) that took the form and returned a set of components that all had the correct typing but were custom and had my styling applied. In practice, this looks something like this for my InputField /***** COMPONENT START *****/
export const generateInputField = <T extends FormApi<any, any>>(form: T) => {
/***** TYPE DEFINITIONS *****/
type TData = T extends FormApi<infer _TData, any> ? _TData : never;
type TFormValidator = T extends FormApi<any, infer _TValidator> ? _TValidator : never;
type TValidators = Parameters<UseField<TData, TFormValidator>>[0]['validators']
type TInputField = React.FC<{
name: DeepKeys<TData>;
label?: React.ReactNode;
placeholder?: string;
defaultMeta?: Partial<FieldMeta>;
asyncDebounceMs?: number;
validators?: TValidators;
className?: string;
intrinsic?: InputHTMLAttributes<HTMLInputElement>
}>
/**
* InputField
*/
const InputField: TInputField = ({ name, label, placeholder, defaultMeta, asyncDebounceMs, className, validators, intrinsic = {} }) => {
/***** HOOKS *****/
const { state, handleBlur, handleChange } = useField({
form,
name, // typescript is going to think that name can be an object key but tanstack expects a string
asyncDebounceMs: asyncDebounceMs ?? 200,
defaultMeta,
validators
})
const { errors } = state.meta;
/***** RENDER *****/
// JSX code here This actually works great and is pretty much perfect for types (except for the abysmal typescript performance) but as long as I keep this file closed, it seems to perform fine. I just feel like this shouldn't be this performance intensive if we want to make this kind of abstraction so either I am doing something completely wrong, or perhaps there is some way that the types internally can be improved and I'd love some feedback from someone more familiar with the types/internals of this library to shed some light on that. @fl0ydj Hopefully this solution I have provided for now works in your case |
Beta Was this translation helpful? Give feedback.
-
Thanks for the ideas!
Problem here is still that I have to use any on e.target.value but that seems quite hard to fix. I tried this but doesnt help anything:
Any ideas? Also curious, I am using a react context to store a reference to the form and use it in deeply nested components and wondering if thats an idiomatic. Seems to work quite nicely. |
Beta Was this translation helpful? Give feedback.
-
Hey! Love tanstack form and recently switched from another library.
A question about the correct usage of generics for reuseable fields
The code below results in a type error on the name prop. How should this be typed correctly?
Beta Was this translation helpful? Give feedback.
All reactions