Skip to content

Conflicting type and usage for useForm->errors #177

Closed

Description

@mpressen

in /node_modules/@inertiajs/react/types/useForm.d.ts we can see that :
errors: Partial<Record<keyof TForm, string>>

But in the docs, we have this usage :
redirect_to new_user_url, inertia: { errors: user.errors }

which actually create errors with type Partial<Record<keyof TForm, string[]>> instead.

Should we do something about it ?

Activity

  1. pricci1 commented on Mar 9, 2025

    @pricci1

    Maybe in Laravel it is a string?

    Anyways, I added this patch for now

    diff --git a/node_modules/@inertiajs/react/types/useForm.d.ts b/node_modules/@inertiajs/react/types/useForm.d.ts
    index de427dc..7cee9a6 100644
    --- a/node_modules/@inertiajs/react/types/useForm.d.ts
    +++ b/node_modules/@inertiajs/react/types/useForm.d.ts
    @@ -7,7 +7,7 @@ type FormOptions = Omit<VisitOptions, 'data'>;
     export interface InertiaFormProps<TForm extends FormDataType> {
         data: TForm;
         isDirty: boolean;
    -    errors: Partial<Record<keyof TForm, string>>;
    +    errors: Partial<Record<keyof TForm, string[]>>;
         hasErrors: boolean;
         processing: boolean;
         progress: Progress | null;
  2. skryukov commented on Apr 11, 2025

    @skryukov
    Collaborator

    Another option is to define a global re-export:

    // app/frontend/types/inertia-rails.d.ts
    
    import type { FormDataConvertible } from "@inertiajs/core"
    import type { InertiaFormProps as OriginalProps } from "@inertiajs/react"
    
    type FormDataType = Record<string, FormDataConvertible>
    
    declare module "@inertiajs/react" {
      interface InertiaFormProps<TForm extends FormDataType>
        extends Omit<OriginalProps<TForm>, "errors" | "setError"> {
        errors: Partial<Record<keyof TForm, string[]>>
        setError(field: keyof TForm, value: string[]): void
        setError(errors: Record<keyof TForm, string[]>): void
      }
    
      export { InertiaFormProps }
    
      export function useForm<TForm extends FormDataType>(
        initialValues?: TForm,
      ): InertiaFormProps<TForm>
      export function useForm<TForm extends FormDataType>(
        rememberKey: string,
        initialValues?: TForm,
      ): InertiaFormProps<TForm>
    }

    But tbh, I still want to serialize errors before sending to the frontend, so in the starter kit I go with the flow and define a controller helper that turns arrays into strings:

    def inertia_errors(model, full_messages: true)
      {
        errors: model.errors.to_hash(full_messages).transform_values(&:to_sentence)
      }
    end

    then I just call it on redirects:

    redirect_to sign_up_path, inertia: inertia_errors(@user)
    
    # to me this doesn't look better tbh:
    redirect_to sign_up_path, inertia: {errors: @user.errors.to_hash(true)}
    
    # or even this:
    redirect_to sign_up_path, inertia: {errors: @user.errors}
  3. bknoles commented on Apr 12, 2025

    @bknoles
    Collaborator

    I like the path to match what the JS side expects. What if we added a slightly modified inertia_errors method to Inertia Rails:

    def inertia_errors(model, full_messages: true)
      model.errors.to_hash(full_messages).transform_values(&:to_sentence)
    end
    
    # in the controller
    redirect_to sign_up_path, inertia: {errors: inertia_errors(@user)}

    If we wanted to be fancy we could (optionally, via the configuration) automatically transform an errors prop to a string (if it's an ActiveRecord object) inside the renderer.

    # lib/inertia_rails/renderer.rb
    
    def deep_transform_props(props, parent_path = [])
      props.each_with_object({}) do |(key, prop), transformed_props|
        current_path = parent_path + [key]
    
        if prop.is_a?(Hash) && prop.any?
          # stuff here
        elsif keep_prop?(prop, current_path)
          if key == :errors && prop.is_a?(ActiveRecord::Base) && configuration.stringify_active_record_errors
            transformed_prop[key] = prop.errors.to_hash(true).transform_values(&:to_sentence)
          else
            # existing case statement here
          end
        end
      end
    end
  4. skryukov commented on Nov 23, 2025

    @skryukov
    Collaborator

    Inertia now provides a way to define type of error messages by declaring InertiaConfig.errorValueType, see example here: https://github.com/inertiajs/inertia-rails/blob/master/lib/generators/inertia/install/templates/react/types/globals.d.ts#L6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions