Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conflicting type and usage for useForm->errors #177

Open
mpressen opened this issue Dec 19, 2024 · 3 comments
Open

Conflicting type and usage for useForm->errors #177

mpressen opened this issue Dec 19, 2024 · 3 comments

Comments

@mpressen
Copy link

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 ?

@pricci1
Copy link

pricci1 commented Mar 9, 2025

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;

@skryukov
Copy link
Contributor

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}

@bknoles
Copy link
Collaborator

bknoles commented Apr 12, 2025

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants