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

SWRMutation.trigger infers to undefined #2280

Closed
HaNdTriX opened this issue Dec 12, 2022 · 3 comments
Closed

SWRMutation.trigger infers to undefined #2280

HaNdTriX opened this issue Dec 12, 2022 · 3 comments

Comments

@HaNdTriX
Copy link

HaNdTriX commented Dec 12, 2022

Bug report

Observed Behavior

The new useSWRMutation->trigger method infers to FetcherResponse<Data> | undefined

Expected Behavior

The new useSWRMutation->trigger method should infer to FetcherResponse<Data>

Repro Steps / Code Example

import useSWRMutation from "swr/mutation";

const fetcher = async () => ({ foo: "bar" })

export default function MyPage() {
  const { trigger } = useSWRMutation("/some/key", fetcher);

  return (
    <button
      onClick={async () => {
        const result = await trigger();
        result.foo // => 'result' is possibly 'undefined'.ts(18048)
      }}
    />
  );
}

Additional Context

Versions:

"typescript": "^4.9.3"
"swr": "^2.0.0"

Affected Code

swr/mutation/types.ts

Lines 58 to 61 in 2eb83c9

trigger: (
extraArgument?: ExtraArg,
options?: SWRMutationConfiguration<Data, Error, ExtraArg, SWRMutationKey>
) => Promise<Data | undefined>

Integrated Example

When trying to use queries and mutations the types will clash because mutate expects an result not undefined.
See the inline comment below:

import useSWR from "swr";
import useSWRMutation from "swr/mutation";

const fetcher = async () => ({ foo: "bar" })

export default function MyPage() {
  const { mutate } = useSWR("/some/key", fetcher);
  const { trigger } = useSWRMutation("/some/key", fetcher);

  return (
    <button
      onClick={async () => {
        mutate(trigger(), { // <-  Argument of type 'Promise<{ foo: string; } | undefined>' is not assignable to parameter of type '{ foo: string; } | Promise<{ foo: string; }> | MutatorCallback<{ foo: string; }> | undefined'. ...
          optimisticData: {
            foo: 'baz'
          }
        })
      }}
    />
  );
}
@felipeozalmeida
Copy link

I'm with you here. I don't know under what conditions trigger may return undefined and how to handle that case.

promer94 added a commit to promer94/swr that referenced this issue Feb 11, 2023
promer94 added a commit to promer94/swr that referenced this issue Feb 11, 2023
shuding pushed a commit that referenced this issue Feb 11, 2023
* types: fix some mutation type issue

close #2418 #2406 #2280

* chore: update

* fix lint
@felipeozalmeida
Copy link

The type below is the current definition of trigger from SWRMutationResponse in SWR v2.1.5 and it still includes undefined. Maybe this issue is not 100% closed? Or is my understanding wrong? Is there a valid scenario for undefined here?

/**
 * Function to trigger the mutation. You can also pass an extra argument to
 * the fetcher, and override the options for the mutation hook.
 */
trigger: [ExtraArg] extends [never]
  ? <SWRData = Data>(
      extraArgument?: null,
      options?: SWRMutationConfiguration<
        Data,
        Error,
        ExtraArg,
        SWRMutationKey,
        SWRData
      >
    ) => Promise<Data | undefined>
  : <SWRData = Data>(
      extraArgument: ExtraArg,
      options?: SWRMutationConfiguration<
        Data,
        Error,
        ExtraArg,
        SWRMutationKey,
        SWRData
      >
    ) => Promise<Data | undefined>

I currently have this workaround written in one of my codebases:

Known Issues

Since SWR 2.0.0

The return type of the trigger function returned by SWRMutationHook always includes undefined as a possible value. It isn't known under what circumstances a successful API call with actual JSON response may still return undefined without being an error. Although not ideal, a non-null assertion operator is sufficient to remove both null and undefined from the resulting type. Nonetheless, an issue was created to discuss this problem.

// This is a simple one-off example.
// Please, use the existing rationale, code and folder structure for API calls.
const { trigger: createTodo } = useSWRMutation("/api/todos", async (key, { arg }) => {
  const response = await axios.post<CreateTodoResponseData>(key, arg)
  return response.data
})

const handleSubmit = useCallback(async (data) => {
  // Note the exclamation mark.
  // From: CreateTodoResponseData | undefined
  // To: CreateTodoResponseData
  const createdTodo = (await createTodo(data))!
}, [createTodo])

@mattcasey
Copy link

mattcasey commented Feb 20, 2024

I would love either an explanation why it can be undefined, or a fix to the types as well. The docs don't mention anything: https://swr.vercel.app/docs/mutation#useswrmutation-return-values

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

No branches or pull requests

5 participants