React and Typescript creating useReducer "no overload matches this call"

huangapple go评论61阅读模式
英文:

React and Typescript creating useReducer "no overload matches this call"

问题

Here's the translation of the code portion you provided:

import { useCallback, useReducer } from "react";

const ARTIST_REDUCER_TYPES = {
  ADD: "ADD",
};

const artistArray = [...Object.values(ARTIST_REDUCER_TYPES)] as const;

type ActionReturnedTypes = (typeof artistArray)[number];

type ReducerStateType = {
  artist: { name: string };
  albums: { name: string, released: number }[];
  topTracks: { name: string, released: number }[];
};

type ReducerAction = {
  type: ActionReturnedTypes;
  payload: ReducerStateType;
};

const artistInitState = {
  artist: { name: "" },
  albums: [{ name: "", released: 0 }],
  topTracks: [{ name: "", released: 0 }],
};

export const useArtistResults = (initialState: typeof artistInitState) => {
  const [artistDetails, dispatch] = useReducer(
    (state: ReducerStateType, action: ReducerAction): ReducerStateType => {
      switch (action.type) {
        case ARTIST_REDUCER_TYPES.ADD: {
          if (!action.payload) {
            throw new Error("ADD action requires a payload");
          }

          return {
            ...state,
            artist: action.payload.artist,
            albums: action.payload.albums,
            topTracks: action.payload.topTracks,
          };
        }
        default:
          return state; // You should add a default case to return the state unchanged
      }
    },
    artistInitState
  );

  const setProfile = useCallback(
    (artist, albums, topTracks) => {
      dispatch({
        type: "ADD",
        payload: {
          artist,
          albums,
          topTracks,
        },
      });
    },
    []
  );
};

I've translated the code, but please note that code-related issues like the error you mentioned require a closer look and debugging within the development environment. If you have further questions or need assistance with the error, feel free to ask.

英文:
import { useCallback, useReducer } from "react";
const ARTIST_REDUCER_TYPES = {
ADD: "ADD",
};
const artistArray = [...Object.values(ARTIST_REDUCER_TYPES)] as const;
type ActionReturnedTypes = (typeof artistArray)[number];
type ReducerStateType = {
artist: { name: string };
albums: { name: string, released: number }[];
topTracks: { name: string released: number }[];
};
type ReducerAction = {
type: ActionReturnedTypes;
payload: ReducerStateType;
};
const artistInitState = {
artist: { name: ""},
albums: [{name: "", released: 0}],
topTracks: [{name: "", released: 0}],
};
export const useArtistResults = (initialState: typeof artistInitState) => {
const [artistDetails, dispatch] = useReducer(
(state: ReducerStateType, action: ReducerAction): ReducerStateType => {
switch (action.type) {
case ARTIST_REDUCER_TYPES.ADD: {
if (!action.payload) {
throw new Error("ADD action requires a payload");
}
return {
...state,
artist: action.payload.artist,
albums: action.payload.albums,
topTracks: action.payload.topTracks,
};
}
}
},
artistInitState
);
const setProfile = useCallback(
(artist, albums, topTracks) => {
dispatch({
type: "ADD",
payload: {
artist,
albums,
topTracks,
},
});
},
[]
);

This is constantly returning this error:

>No overload matches this call.

If I take off the type for the state parameter the error goes away. I just don't seem to know what is causing this. Does this have something to do with the state object not matching the initial state?

I'm so confused

答案1

得分: 1

尝试从 reducer 函数中删除显式的 ReducerStateType 返回类型,并在 ARTIST_REDUCER_TYPES 上添加 const 断言:

const ARTIST_REDUCER_TYPES = {
  ADD: "ADD",
} as const;

这将把该值的类型从:

{
   ADD: string
}

更改为:

{
  readonly ADD: "ADD"
}

这样 TypeScript 就能知道您的 reducer 内部的 switch 是穷尽的。

英文:

Try removing the explicit ReducerStateType return type from the reducer function and adding a const assertion to ARTIST_REDUCER_TYPES:

const ARTIST_REDUCER_TYPES = {
  ADD: "ADD",
} as const;

This changes the type of that value from:

{
   ADD: string
}

to:

{
  readonly ADD: "ADD"
}

This allows TypeScript to know that the switch inside your reducer is exhaustive.

答案2

得分: 0

这是一个关于状态实际类型与初始状态略有不正确的问题。

上面的代码是我尽量将其复制性降至最低的尝试。实际上,我的代码和状态比我上面提供的示例要复杂得多,因此这不是一个很好的示例。

我所需要做的就是修复initialState

以下是代码的一部分,只包含翻译:

export const artistInitState = {
  artist: {
    external_urls: { spotify: "" },
    followers: { href: null, total: 0 },
    genres: [],
    href: "",
    id: "",
    images: [{ height: 0, url: "", width: 0 }],
    name: "",
    popularity: 0,
    type: "",
    uri: "",
  },
  // 省略其他部分...
};

type ReducerStateType<T> = {
  artist: ArtistDetailsType;
  albums: AlbumDetailsType[] | T;
  topTracks: TopTracksDetailsType[] | T;
};

export const useArtistResults = (initialState: typeof artistInitState) => {
  // 省略其他部分...
};

希望这有助于您理解代码中的部分内容。如果您需要更多翻译,请随时告诉我。

英文:

This was an issue with the actual type for the state being slightly incorrect with the initial state.

My above code was an attempt at making it as reproducible as possible. In reality, my code and state is a lot larger than the example I put above so it wasn't a good example

All I had to do was fix the initialState

export const artistInitState = {
artist: {
external_urls: { spotify: "" },
followers: { href: null, total: 0 },
genres: [],
href: "",
id: "",
images: [{ height: 0, url: "", width: 0 }],
name: "",
popularity: 0,
type: "",
uri: "",
},
albums: [
{
album_group: "",
album_type: "",
artists: [],
available_markets: [],
external_urls: { spotify: "" },
href: "",
id: "",
images: [{ height: 0, url: "", width: 0 }],
name: "",
release_date: "",
release_date_precision: "",
total_tracks: 0,
type: "",
uri: "",
},
],
topTracks: [
{
album: {
album_group: "",
album_type: "",
href: "",
},
artists: [],
disc_number: 0,
duration_ms: 0,
explicit: false,
external_ids: { isrc: "" },
external_urls: {
spotify: "",
},
href: "",
id: "",
is_local: false,
is_playable: true,
name: "",
popularity: 0,
preview_url: "",
track_number: 0,
type: "",
uri: "",
},
],
};

There were a few mistakes in there so it didn't match the ReducerStateType

type ReducerStateType<T> = {
artist: ArtistDetailsType;
albums: AlbumDetailsType[] | T;
topTracks: TopTracksDetailsType[] | T;
};
export const useArtistResults = (initialState: typeof artistInitState) => {
const [artistDetails, dispatch] = useReducer(
(
state: ReducerStateType<NoAlbumOrTracksType>,
action: ReducerAction
): ReducerStateType<NoAlbumOrTracksType> => {
switch (action.type) {
case ARTIST_REDUCER_TYPES.ADD: {
if (!action.payload) {
throw new Error("ADD action requires a payload");
}
let albums: AlbumDetailsType[] | { noAlbums: "no albums" } = action
.payload.albums.length
? [
...new Map(
action.payload.albums.map((item) => [item.name, item])
).values(),
]
: { noAlbums: "no albums" };
let topTracks: TopTracksDetailsType[] | { noTracks: "no tracks" } =
action.payload.topTracks.length
? action.payload.topTracks
: { noTracks: "no tracks" };
return {
...state,
artist: action.payload.artist,
albums,
topTracks,
};
}
default:
return { ...state };
}
},
initialState
);
const setProfile = useCallback<ArtistAndAlbumStateSetter>(
(artist, albums, topTracks) => {
dispatch({
type: "ADD",
payload: {
artist,
albums,
topTracks,
},
});
},
[]
);
const { artist, albums, topTracks } = artistDetails;
return { artist, albums, topTracks, setProfile };
};

huangapple
  • 本文由 发表于 2023年5月7日 02:47:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76190568.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定