TanStackT
TanStack7mo ago
19 replies
ordinary-sapphire

Is there a way to get the type of a form and form state from form options?

I'm trying to create a generic stepper form where certain parts are only visible if other parts are complete or have certain answers. Currently I'm doing this with nested <form.Subscribe> components, but it's pretty ugly. I'm hoping to do something like this:

export type Step<FormOpts, StepId extends string> = {
  id: StepId;
  dependencies?: StepId[];
  shouldRender: (state: FormState<FormOpts>) => boolean;
  render: (props: { form: Form<FormOpts> }) => React.ReactNode;
};

function shouldRenderStep<FormOpts, StepId extends string>(
  step: Step<FormOpts, StepId>,
  state: FormState<FormOpts>,
  allSteps: Step<FormOpts, StepId>[]
): boolean {
  if (!step.shouldRender(state)) {
    return false;
  }

  const dependencies = step.dependencies ?? [];

  for (const depId of dependencies) {
    const dependentStep = allSteps.find((s) => s.id === depId);

    if (!dependentStep) {
      throw new Error(`Dependency step with id "${depId}" not found.`);
    }

    if (!dependentStep.shouldRender(state)) {
      return false;
    }
  }

  return true;
}

export function StepperForm<FormOpts, StepId extends string>({
  form,
  steps,
}: {
  form: Form<FormOpts>;
  steps: Step<FormOpts, StepId>[];
}) {
  return (
    <>
      {steps.map((step) => (
        <form.Subscribe
          selector={(state) => shouldRenderStep(step, state, steps)}
          key={step.id}
        >
          {(shouldRender) => shouldRender && <step.render form={form} />}
        </form.Subscribe>
      ))}
    </>
  );
}


But I'm not sure how to type Form and FormState. It looks like it's possible by kind of duplicatign the type of createFormHooks, but it ends up with like 9 generics and it's just nasty. I'm wondering if there's a better built-in way to do this (some type that gives the return type of
useAppForm
given the form options?) or if I'm going about this all wrong and should be taking a different approach.
Was this page helpful?