vercel / swr

React Hooks for Data Fetching
https://swr.vercel.app
MIT License
30.53k stars 1.22k forks source link

Regression in 2.2.4: Type issue with useSWR: fetcher mistaken for config #2809

Open fabb opened 1 year ago

fabb commented 1 year ago

Bug report

Description / Observed Behavior

The typings of useSWR no longer correctly infer the fetcher type. The type error indicates that typescript mistakes the fetcher for a config:

    Type '([_key, ...ids]: [string, ...number[]]) => Promise<MyResponse>' has no properties in common with type 'Partial<PublicConfiguration<any, any, BareFetcher<any>>>'.ts(2769)

Expected Behavior

It should compile like in 2.2.2

Repro Steps / Code Example

See https://codesandbox.io/s/swr-type-issue-qmjk9g?file=/src/App.tsx

Additional Context

SWR version 2.2.3-2.2.4.

koba04 commented 1 year ago

As your code sandbox example, you pass a URL as the key, so the type of the key is string, not [string, ...number]. If you want to pass ids to the fetcher, you have to pass them as the key.

  const { data, error } = useSWR(
    ["https://api.github.com/repos/vercel/swr", 1,2,3],
    fetcher
  );
lukeg90 commented 1 year ago

I'm getting a similar typescript error after updating to 2.2.4:

Type '(url: Input, options?: Options | undefined) => Promise<unknown>' has no properties in common with type 'Partial<PublicConfiguration<Output, string | Error, BareFetcher<Output>>>'.ts(2769)

Here's my code:

import useSWR, { type Key } from 'swr';
import ky from 'ky';

function useApi<Output>(key: Key) {
  return useSWR<Output, string | Error>(
    key,
    async (...args: Parameters<typeof ky>) => await ky(...args).json(),
  );
}
sambauers commented 1 year ago

I'm getting a similar typescript error after updating to 2.2.4:

Type '(url: Input, options?: Options | undefined) => Promise<unknown>' has no properties in common with type 'Partial<PublicConfiguration<Output, string | Error, BareFetcher<Output>>>'.ts(2769)

Here's my code:

import useSWR, { type Key } from 'swr';
import ky from 'ky';

function useApi<Output>(key: Key) {
  return useSWR<Output, string | Error>(
    key,
    async (...args: Parameters<typeof ky>) => await ky(...args).json(),
  );
}

I found that a similar issue in my code was triggered by passing in an array of strings as the key to the fetcher. It seems that a change between 2.2.2 and 2.2.3 caused that to no longer be a valid type without some additional work by the user.

I think this (or something similar) may work for you:

import useSWR, { type Key } from 'swr';
import ky from 'ky';

function useApi<Output>(key: Key) {
  return useSWR<Output, string | Error, Parameters<typeof ky>>(
    key,
    async (...args) => await ky(...args).json(),
  );
}
martinharyanto commented 1 year ago

Confirmed this also happens to me

const fetcher = (url: string, token: string) => axios.get(url, { headers: { 'x-auth-token': token } }).then((res) => res.data)

const { data, error, isLoading } = useSWR<Records<ItemStatusLogTableFieldSet>, Error>(
    [`/api/maas/items/logs/${recordId}`, auth.token],
    ([url, token]: string[]) => fetcher(url, token)
  )

it throws a TS Error

No overload matches this call.
  The last overload gave the following error.
    Type '([url, token]: string[]) => Promise<any>' has no properties in common with type 'Partial<PublicConfiguration<Records<ItemStatusLogTableFieldSet>, Error, BareFetcher<Records<ItemStatusLogTableFieldSet>>>>'

Coming back after 2 months to the project, updating packages to latest and everything is breaking.

huksley commented 1 year ago

This is also happening to me in 2.2.4

TS2769: No overload matches this call.
  The last overload gave the following error.
    Type '([id, _type]: string[]) => Promise<{ _id: string; name: string; }[]>' has no properties in common with type 'Partial<PublicConfiguration<any, any, BareFetcher<any>>>'.
    160 |   const { data: categories } = useSWR(
    161 |     [user?.companyId, "categories"],
  > 162 |     ([id, _type]: string[]) => getCategories(id)
        |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    163 |   );
martinharyanto commented 1 year ago

For those who still facing the issue, I fixed mine by updating the package to "swr": "^2.0.3" For me this is the latest that did not have this issue

joel-daros commented 8 months ago

A simple way to solve is to explicitly specify your key types:

// remember that for multiple parameter you need to use the Array notation
const fetcher = async ([url, token]: [
  url: string,
  token: string,
]) => {
  // your axios call
 return true;
};

export const useFoo = () => {
  // the third generic parameter is the shape of your key.
  const { data } = useSWR<boolean, AxiosError, [url: string, token: string]>(["http://foo/.bar", "mySecretToken"], fetcher);

}