Search code examples
typescriptnext.jsreact-typescripttypescript-types

NextJS TypeScript types errors


I have a problem with executing this function:

"use server";

export const addProduct = async (formData: FormData, imageUrl: string) => {
  const productName = formData.get("productName")?.toString();
  const description = formData.get("description")?.toString();
  const location = formData.get("location")?.toString();

  if (!productName || !description || !imageUrl || !location) {
    throw Error("Missing required fields");
  }
};

<form className="flex flex-col gap-4 text-lg" action={addProduct(imageUrl)}>

Errors:

Type '(formData: FormData, imageUrl: string) => Promise<never>' is not assignable to type 'string | ((formData: FormData) => void) | undefined'. Type '(formData: FormData, imageUrl: string) => Promise<never>' is not assignable to type '(formData: FormData) => void'. Target signature provides too few arguments. Expected 2 or more, but got 1.

Adding arguments to the addProduct function didn't help, I'm guessing that probably types are incorrect.


Solution

  • "addProduct" is a function that returns nothing, i.e void.

    You're doing action={addProduct(...)} which means "void" is being passed to "action", NOT the function itself. You want to give the form the function itself in order for the form to CALL on that function.

    Now, if addProduct didn't take any arguments, you'd be able to do action={addProduct}. However, how would the form know to pass imageUrl?

    One way to do this is an inline function:

    <form action={(data: FormData) => addProduct(data, imageUrl)}>
    

    Another way is to curry the addProduct function:

    const addProduct = (imageUrl: string) => async (formData: FormData) => {
      const productName = formData.get("productName")?.toString();
      const description = formData.get("description")?.toString();
      const location = formData.get("location")?.toString();
    
      if (!productName || !description || !imageUrl || !location) {
        throw Error("Missing required fields");
      }
    };
    

    Then:

    <form action={addProduct(imageUrl)}>
    

    And calling addProduct(imageUrl) will now return a function that takes only the FormData as an argument, which is what the form tag expects.

    You should also probably be asking yourself why imageUrl is an argument in the first place. Maybe you should store it in a state and just read the state from inside of the function instead of expecting it as a parameter.