TS - многоразовый перехватчик запроса API - тип не может быть назначен типу IUseApiHook

Что я пытаюсь сделать?

Я хочу создать функцию, которая может выполнять любой тип запроса API для внешнего приложения. В принципе, я хочу пофантазировать.

Проблема?

Я нахожусь над головой, и мне нужен еще один глаз, чтобы взглянуть на мой сломанный подход.

Вот ошибка, которую я получаю из приведенного ниже кода:

      Type '<T>(options: TApiHookOptions) => { data: Accessor<T | null>; error: Accessor<Error | null>; loading: Accessor<boolean>; request: void; }' is not assignable to type 'IUseApiHook'.
  Call signature return types '{ data: Accessor<unknown>; error: Accessor<Error | null>; loading: Accessor<boolean>; request: void; }' and 'TApiHook<T>' are incompatible.
    The types of 'data' are incompatible between these types.
      Type 'Accessor<unknown>' is not assignable to type 'T'.
        'T' could be instantiated with an arbitrary type which could be unrelated to 'Accessor<unknown>'.ts(2322)

Код (все здесь):

      import { createEffect, createSignal } from "solid-js";
import axios from "axios";

export type TApiResponse<T> = {
  data: T;
  error: Error | null;
};

export type TApiHook<T> = {
  data: T | null;
  error: Error | null;
  loading: boolean;
  request: () => void;
};

export type TApiHookOptions = {
  url: string;
  method?: "get" | "post" | "put" | "delete";
  data?: any;
};

export interface IUseApiHook {
  <T>(options: TApiHookOptions): TApiHook<T>;
}

export const useApiHook: IUseApiHook = <T>(options: TApiHookOptions) => {
  const [data, setData] = createSignal<T | null>(null);
  const [error, setError] = createSignal<Error | null>(null);
  const [loading, setLoading] = createSignal(false);

  const request = createEffect(() => {
    setLoading(true);
    axios({
      url: options.url,
      method: options.method || "get",
      data: options.data,
    })
      .then((response) => {
        setData(response.data);
        setError(null);
      })
      .catch((error) => {
        setError(error);
      })
      .finally(() => {
        setLoading(false);
      });
  });

  return {
    data,
    error,
    loading,
    request,
  };
};

1 ответ

Я не знаю, но глядя на документы и типы, первое возвращаемое значение — это функция, которая возвращает значение с сохранением состояния.

Это означает, что вы хотите сделать это:

        return {
    data: data(),
    error: error(),
    loading: loading(),
    request,
  };

Но есть еще проблема с request. Вы набрали его как функцию, но createEffectвозвращается void. Я не думаю, что вам нужен эффект здесь вообще (эффект — это функция, запускаемая после любого рендера, в котором изменились зависимости). Это обратный вызов (то, что вы запускаете, когда пользователь выполняет действие), а не эффект. В простой реакции вы бы использовали useCallback()запомнить эту функцию. Но я думаю, просто запомнить его?

        const request = createMemo(() => {
    setLoading(true);
    axios({
      url: options.url,
      method: options.method || "get",
      data: options.data,
    })
      .then((response) => {
        setData(response.data);
        setError(null);
      })
      .catch((error) => {
        setError(error);
      })
      .finally(() => {
        setLoading(false);
      });
  }, options);

Хотя я не уверен на 100%, что solid-jsрекомендовал бы здесь, или если требуется мемоизация (это требуется в простой реакции, если эта функция будет использоваться в качестве зависимостей для любого другого хука).

Рабочая площадка

Другие вопросы по тегам