根据其他参数输入函数参数

问题描述 投票:0回答:1

我的最终目标是像这样使用 useModel 钩子:

useModel(Art, "get", { id: 7 })
useModel(Art, "post", { data: { title: "Art title" } })

但是我在正确输入该钩子的第三个参数时遇到问题,因为它依赖于方法(第二个参数)。所有模型都具有相同的方法和相同的参数,并且从保存这些方法的同一个类进行扩展。方法参数可能不同,如下面的代码示例所示。

class BaseApiModel {
  protected static endpoint = "";
  public static key = "";

  ...

  static async get<T>(id?: number, params?: QueryFilterParams) {
    const axios = this.getAxiosInstance();

    const response: ResourceResponse<T> = await axios({
      method: "GET",
      url: id ? `${this.endpoint}/${id}` : this.endpoint,
      params,
    });

    // TODO: type the response (ResourceResponse<T> | CollectionResponse<T> | PaginatedResponse<T> | CountResponse)
    return response;
  }

  static async post<T>(data: Omit<T, "id">) {
    const axios = this.getAxiosInstance();

    const response: ResourceResponse<T> = await axios({
      method: "POST",
      url: this.endpoint,
      data,
    });

    return response;
  }

...

}

这是将传递给钩子的示例模型:

class Art extends BaseApiModel {
  protected static endpoint = "/art";
  public static key = "art";

  id!: number;
  title!: string;
  description!: string;
  image?: File;
}

这是钩子:

type Methods = "get" | "post" | "put" | "patch" | "delete";
function useModel<T extends typeof BaseApiModel>(
  model: T,
  method: Methods,
  options?: Record<string, any>
) {
  const query = useQuery({
    queryKey: [model.key, method, options],
    queryFn: model[method](options),
    enabled: method === "get",
  });

  const mutation = useMutation({
    mutationKey: [model.key, method, options],
    mutationFn: model[method](options),
  });

  if (method === "get") {
    return query;
  }
  return mutation;
}
typescript typescript-generics
1个回答
0
投票

您可以对第三个参数使用条件类型:

游乐场

type Methods = "get" | "post" | "put" | "patch" | "delete";

type QueryFilterParams = Record<string, string>;

function useModel<T extends typeof BaseApiModel, M extends Methods>(
  model: T,
  method: M,
  options?: M extends 'get' ? {id?: number, params?: QueryFilterParams } : M extends 'post' ? {data: Omit<InstanceType<T>, "id"> }  : never
) {
  
}

type ResourceResponse<T> = T;

class BaseApiModel{
  protected static endpoint = "";
  public static key = "";

  static async get<T>(id?: number, params?: QueryFilterParams) {

    const response: ResourceResponse<T> = await axios({
      method: "GET",
      url: id ? `${this.endpoint}/${id}` : this.endpoint,
      params,
    });

    // TODO: type the response (ResourceResponse<T> | CollectionResponse<T> | PaginatedResponse<T> | CountResponse)
    return response;
  }

  static async post<T>(data: Omit<T, "id">) {

    const response: ResourceResponse<T> = await axios({
      method: "POST",
      url: this.endpoint,
      data,
    });

    return response;
  }
}

class Art extends BaseApiModel{
  title = 'Art title';
}

useModel(Art, "get", { id: 7 })
useModel(Art, "post", { data: { title: "Art title" } })
© www.soinside.com 2019 - 2024. All rights reserved.