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

fix: fix the type of the argument of KeyedMutator for populateCache #2933

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

Key5n
Copy link

@Key5n Key5n commented Apr 8, 2024

closes #2975

What this PR does

This PR fixes a type error problem related to populateCache and bound mutate.

Now, the first argument of bound mutate only accepts the type of the returned value of fetcher by useSWR.

But in order to make use of populateCache, the first argument of mutate should accept any type of API fetching result.

So I changed the type of the first argument from Data (which is the type of data useSWR fetches) into MutationData (which is the type of the data returned by the mutator)

In addition, I changed types in infinite since it had error when I changed the type of KeyedMutator .

@Key5n Key5n requested review from shuding and huozhi as code owners April 8, 2024 19:59
Copy link

codesandbox-ci bot commented Apr 8, 2024

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Comment on lines +431 to +435
<Data = any, MutationData = Data>(
key: Arguments,
data?: T | Promise<T> | MutatorCallback<T>,
opts?: boolean | MutatorOptions<Data, T>
): Promise<T | undefined>
data?: MutationData | Promise<MutationData> | MutatorCallback<MutationData>,
opts?: boolean | MutatorOptions<Data, MutationData>
): Promise<MutationData | undefined>
Copy link
Author

@Key5n Key5n Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just refactoring for name consistency.
Since there is @typeParam MutationData comment docs, I think the generics parameter T should follow that.

Copy link
Member

@huozhi huozhi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, can we add a test?

@Key5n
Copy link
Author

Key5n commented Jun 1, 2024

Sure!
Thank you for comment.

If you want to modify my PR, please do at your mercy.

@Key5n
Copy link
Author

Key5n commented Jun 7, 2024

Sorry, I didn't notice that some tests were unpassed.
I will fix it.

@Key5n
Copy link
Author

Key5n commented Jun 17, 2024

@huozhi

A PR I submitted fails some tests, so I've changed almost of whole things and add tests.
Sorry for begging you reviews again.

I changed the type KeyedMutator using overload function, making populateCache is necessary when MutationData (the type of the first argument of bound mutate) is different from the type of Data.

This achieves strict type attaching.

| MutatorCallback<Data[]>,
opts?: undefined | boolean | SWRInfiniteMutatorOptions<Data[], T>
) {
function (data?: any, opts?: any) {
Copy link
Author

@Key5n Key5n Jun 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I request you for comments for attaching any type to the arguments.

The reason for attachching any is below.

I thought the type of the arguments data and opts should be any when using function overload since signatures in KeyedMutator couldn't be distinguished at this point.

The type of data argument at this point should be Data | Promise<Data | undefined> | MutatorCallback<Data>| MutationData | Promise<MutationData | undefined> | MutatorCallback<MutationData> | undefined.

But I I do so and pass the data to swr.mutate, It gives the following error.

No overload matches this call.
  Overload 1 of 2, '(data?: Data[] | Promise<Data[] | undefined> | MutatorCallback<Data[]> | undefined, opts?: boolean | MutatorOptions<Data[], Data[]> | undefined): Promise<...>', gave the following error.
    Argument of type 'Data[] | MutationData | Promise<Data[] | undefined> | MutatorCallback<Data[]> | Promise<MutationData | undefined> | MutatorCallback<...> | undefined' is not assignable to parameter of type 'Data[] | Promise<Data[] | undefined> | MutatorCallback<Data[]> | undefined'.
      Type 'MutationData' is not assignable to type 'Data[] | Promise<Data[] | undefined> | MutatorCallback<Data[]> | undefined'.
        Type 'MutationData' is not assignable to type 'Promise<Data[] | undefined>'.
  Overload 2 of 2, '(data: MutationData | Promise<MutationData | undefined> | MutatorCallback<MutationData>, opts: Omit<...> & { ...; }): Promise<...>', gave the following error.
    Argument of type 'Data[] | MutationData | Promise<Data[] | undefined> | MutatorCallback<Data[]> | Promise<MutationData | undefined> | MutatorCallback<...> | undefined' is not assignable to parameter of type 'MutationData | Promise<MutationData | undefined> | MutatorCallback<MutationData>'.
      Type 'undefined' is not assignable to type 'MutationData | Promise<MutationData | undefined> | MutatorCallback<MutationData>'.ts(2769)

image

If I could know the type of Data at this point, I can avoid attaching any by comparing the type of Data with MutationData at runtime.

Do you know how to solve this?
I'm waiting for any comments and advices.

Copy link
Author

@Key5n Key5n Jun 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea for how to solve this problem.

  1. use any
  2. tell the callback function about the type of Data and compare it like the following code
// this is invalid code, just for sharing my idea
if (typeof Data === typeof MutationData){
    
} else {
  ...
}
  1. soft type attaching like the following code
    const mutate = useCallback<SWRInfiniteKeyedMutator<Data[]>>(
      // eslint-disable-next-line func-names
      function <MutationData = Data[]>(
        data?:
          | Data
          | Promise<Data | undefined>
          | MutatorCallback<Data>
          | MutationData
          | Promise<MutationData | undefined>
          | MutatorCallback<MutationData>
          | undefined,
        opts?: boolean | SWRInfiniteMutatorOptions<Data[], MutationData>
      ): Promise<Data[] | MutationData | undefined> {

       // contents

        return arguments.length
          ? swr.mutate<Data[]>(
              data as any,
              {
                ...options,
                revalidate: shouldRevalidate
              } as any
            )
          : swr.mutate()
      },
      // swr.mutate is always the same reference
      // eslint-disable-next-line react-hooks/exhaustive-deps
      [infiniteKey, cache]
    )

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

Successfully merging this pull request may close these issues.

bug: type error on updating cache with bound mutate
2 participants