Closed
Description
Describe the bug
First off, thanks for the awesome library!
We have been observing some weird instances of "Type instantiation is excessively deep and possibly infinite". For some files, tsc is even crashing.
Our repo is private so can't share it but we created a couple of custom Fields/components, so maybe you can spot where this is coming from:
- We have been using zod as a form validator on Fields
- We wrap all forms in a form context provider to avoid prop drilling and are passing in reference from useRef(form) as we had some problems with stability in earlier versions (not sure if this still makes any difference).
Code
import type { MutableRefObject } from "react";
import { createContext, useContext } from "react";
import type { useForm } from "@tanstack/react-form";
export const FormContext: React.Context<MutableRefObject<ReturnType<typeof useForm<any>>> | undefined> =
createContext<MutableRefObject<ReturnType<typeof useForm<any>>> | undefined>(undefined);
export function useFormContext<V>(): ReturnType<typeof useForm<V>> {
const form = useContext(FormContext) as MutableRefObject<ReturnType<typeof useForm<V>>> | undefined;
if (!form) {
throw new Error("useFormContext must be used within a FormProvider");
}
return form.current;
}
- We are using custom fields like in the code below
Code
type IsDeepValueString<T, K extends DeepKeys<T>> = DeepValue<T, K> extends string | number | typeof Any
? K
: never;
type StringDeepKeys<T> = {
[P in DeepKeys<T>]: IsDeepValueString<T, P>;
}[DeepKeys<T>];
export const TextField = <V, N extends DeepKeys<V> & StringDeepKeys<V>>(
props: {
name: N;
label?: string;
regexPattern?: string;
rightElement?: ReactNode;
isPassword?: boolean;
extraFieldProps?: Omit<FieldOptions<V, N, any>, "name">;
} & Omit<InputProps, "name" | "label">,
): ReactNode => {
const form = useFormContext<V>();
const { name, label, regexPattern, rightElement, isPassword, ...rest } = props;
return (
<form.Field {...props.extraFieldProps} name={props.name}>
{(field) => {
console.log("ruleAsset", props.name, field.getValue());
return (
<FormControl isInvalid={field.state.meta.isTouched && field.state.meta.errors?.length > 0}>
{props.label && <FormLabel htmlFor={String(props.name)}>{props.label}</FormLabel>}
<InputGroup>
<Input
type={props.isPassword ? "password" : "text"}
value={field.getValue() === Any ? "∞" : (field.getValue() as string)}
name={String(field.name)}
onChange={(e) => {
console.log("ruleasset ruleamount change", e.target.value);
const regex = new RegExp(props.regexPattern ?? "");
console.log("1");
if (e.target.value === "" || !props.regexPattern || regex.test(e.target.value)) {
console.log("2");
//need to cast as we extend string so its not sure it can be assinged properly
field.handleChange(e.target.value as DeepValue<V, N>);
console.log("2.1");
} else if (e.target.value === "∞") {
field.handleChange(Any as DeepValue<V, N>);
}
console.log("3");
}}
onBlur={field.handleBlur}
{...rest}
/>
{props.rightElement !== undefined && <InputRightElement>{props.rightElement}</InputRightElement>}
</InputGroup>
<FormErrorMessage>
{field.state.meta.isTouched && field.state.meta.errors?.join(", ")}
</FormErrorMessage>
</FormControl>
);
}}
</form.Field>
);
};
- We are using some fields where we receive the value from a query. We want to run validation on it and use it with other fields so we decided for the below structure:
Code
export const GasEstimateSimulation = ({
gasField,
metaData,
userCoin,
approval,
}: {
gasField: FieldApi<RequestTransactionValues, FormField.Gas, any>;
metaData: CoinsData | undefined;
userCoin: UserCoin | undefined;
approval: Approval<UserRequestType.RequestTransaction>;
}): ReactNode => {
const currentWorkspace = useCurrentWorkspace();
const assets = useAssets(currentWorkspace);
const estimatedGas = useEstimateGas(getEstimateGasArgsFromApproval(approval));
console.log("Estimate gas error", estimatedGas, getEstimateGasArgsFromApproval(approval));
useEffect(() => {
console.log("setting gas", estimatedGas.data);
if (estimatedGas.data !== gasField.getValue()) {
gasField.handleChange(estimatedGas.data);
}
}, [estimatedGas.data, gasField]);
return (
<TransactionFeeCardFromGasResult
gas={estimatedGas}
network={getNetworkFromApproval(approval)}
userCoin={userCoin}
metaData={metaData}
// isLoading={!assets.isSuccess || !estimatedGas.isSuccess}
fontSize="xs"
// error={estimatedGas.error}
/>
);
};
Your minimal, reproducible example
Steps to reproduce
See examples above
Expected behavior
Less performance issues with type checking
How often does this bug happen?
None
Screenshots or Videos
No response
Platform
macOs
TanStack Form adapter
None
TanStack Form version
0.26.4
TypeScript version
5.5.4
Additional context
We are using the zod form adaptor at the same version (0.26.4)