Skip to content

createInvoice and updateInvoice should maybe have Promise<State> as return type #469

@nemchik

Description

@nemchik

I just worked through chapter 14 https://nextjs.org/learn/dashboard-app/improving-accessibility and took note that TypeScript complains when using useFormState because the action functions (createInvoice and updateInvoice) differ in type from the initialState being passed. I've got my project deployed on Vercel (per the instructions in chapter 6 https://nextjs.org/learn/dashboard-app/setting-up-your-database also see P.S. note on this chapter) and the build log outputs:

[16:39:50.854] Failed to compile.
[16:39:50.855] 
[16:39:50.855] ./app/ui/invoices/create-form.tsx:17:29
[16:39:50.855] Type error: No overload matches this call.
[16:39:50.856]   Overload 1 of 2, '(action: (state: { errors: { customerId?: string[] | undefined; amount?: string[] | undefined; status?: string[] | undefined; }; message: string; } | { message: string; errors?: undefined; }) => { errors: { ...; }; message: string; } | { ...; } | Promise<...>, initialState: { ...; } | { ...; }, permalink?: string | undefined): [state: ...]', gave the following error.
[16:39:50.856]     Argument of type '(prevState: State, formData: FormData) => Promise<{ errors: { customerId?: string[] | undefined; amount?: string[] | undefined; status?: string[] | undefined; }; message: string; } | { ...; }>' is not assignable to parameter of type '(state: { errors: { customerId?: string[] | undefined; amount?: string[] | undefined; status?: string[] | undefined; }; message: string; } | { message: string; errors?: undefined; }) => { errors: { ...; }; message: string; } | { ...; } | Promise<...>'.
[16:39:50.856]       Target signature provides too few arguments. Expected 2 or more, but got 1.
[16:39:50.856]   Overload 2 of 2, '(action: (state: { errors: { customerId?: string[] | undefined; amount?: string[] | undefined; status?: string[] | undefined; }; message: string; } | { message: string; errors?: undefined; }, payload: FormData) => { ...; } | ... 1 more ... | Promise<...>, initialState: { ...; } | { ...; }, permalink?: string | undefined): [state: ...]', gave the following error.
[16:39:50.857]     Argument of type '{ message: null; errors: {}; }' is not assignable to parameter of type '{ errors: { customerId?: string[] | undefined; amount?: string[] | undefined; status?: string[] | undefined; }; message: string; } | { message: string; errors?: undefined; }'.
[16:39:50.858]       Type '{ message: null; errors: {}; }' is not assignable to type '{ errors: { customerId?: string[] | undefined; amount?: string[] | undefined; status?: string[] | undefined; }; message: string; }'.
[16:39:50.858]         Types of property 'message' are incompatible.
[16:39:50.858]           Type 'null' is not assignable to type 'string'.
[16:39:50.858] 
[16:39:50.858] �[0m �[90m 15 |�[39m �[36mexport�[39m �[36mdefault�[39m �[36mfunction�[39m �[33mForm�[39m({ customers }�[33m:�[39m { customers�[33m:�[39m �[33mCustomerField�[39m[] }) {�[0m
[16:39:50.858] �[0m �[90m 16 |�[39m   �[36mconst�[39m initialState �[33m=�[39m { message�[33m:�[39m �[36mnull�[39m�[33m,�[39m errors�[33m:�[39m {} }�[33m;�[39m�[0m
[16:39:50.858] �[0m�[31m�[1m>�[22m�[39m�[90m 17 |�[39m   �[36mconst�[39m [state�[33m,�[39m dispatch] �[33m=�[39m useFormState(createInvoice�[33m,�[39m initialState)�[33m;�[39m�[0m
[16:39:50.858] �[0m �[90m    |�[39m                             �[31m�[1m^�[22m�[39m�[0m
[16:39:50.858] �[0m �[90m 18 |�[39m�[0m
[16:39:50.858] �[0m �[90m 19 |�[39m   �[36mreturn�[39m (�[0m
[16:39:50.858] �[0m �[90m 20 |�[39m     �[33m<�[39m�[33mform�[39m action�[33m=�[39m{dispatch}�[33m>�[39m�[0m
[16:39:50.932] Error: Command "npm run build" exited with 1
[16:39:51.223] 

(sorry for all the special characters representing colors, it's copied directly from the output)

I found that seemingly the cleanest way to resolve this is to add Promise<State> as the return type of the functions createInvoice and updateInvoice in app/lib/actions.ts

export async function createInvoice(
  prevState: State,
  formData: FormData
): Promise<State> {
export async function updateInvoice(
  id: string,
  prevState: State,
  formData: FormData
): Promise<State> {

I'm still learning quite a bit, and this might not be the best solution, but it does seem to resolve the errors. My initial instinct as to why this might be wrong is both of those functions end with

  revalidatePath("/dashboard/invoices");
  redirect("/dashboard/invoices");

Neither of those lines imply a return of State as far as I can tell, so maybe more information could be provided to clarify what's going on here. I know the Promise part is because the functions are async so they can await the sql calls.


P.S. per the instructions in chapter 6 when deploying from GitHub to Vercel I receive errors about the missing alt attributes that are later added in chapter 14. I figured it would be easy to add on my own but I looked ahead in the material to see it was covered in a later chapter and waited patiently, but there was no indication in chapter 6 that this was expected. This topic could warrant a separate issue, and the outcome could either be to cover the alt attribute requirement sooner so that the Vercel deploy can be successful, or somehow otherwise keep that code commented until it's time to cover accessibility in chapter 14, or at least add some notes in chapter 6 about the deploy failing until you reach chapter 14 to correct the alt attributes (although that is quite a few chapters to cover between 6 and 14).

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