typescript 将react-query trpc查询作为钩子参数传递

ufj5ltwl  于 2023-06-30  发布在  TypeScript
关注(0)|答案(1)|浏览(190)

我想做一个泛型钩子,它接受useQuery作为参数并处理分页。
这意味着我的trpc查询将始终提供skiptake参数。它总是在响应中返回一个count和一个items数组。

function usePagination(query){
  const [skip, take] = useSomethingThatManagesThis();

  const response = query.useQuery({
    skip,
    take,
  });
  
  return useMemo(() => ({
    items: response.data?.items,
    count: response.data?.count
  }), [response]);
}

function MyComponent() {
  const paginated = usePagination(api.user.list);
  
  const firstUserEmail = paginated.items?.[0].email;
}

它在vanilla JavaScript中工作,但我很难正确输入它。
我试图简单地重用trpc客户端类型,但我无法区分请求类型(take,query)和响应类型(items)。

import {
  AnyProcedure,
  AnyQueryProcedure,
  inferProcedureOutput,
} from "@trpc/server";

interface BaseInput {
  skip: number;
  take: number;
}

type UseDatatableArgs<TData extends AnyQueryProcedure> = {
  query?: {
    useQuery: (input: BaseInput) => ProcedureUseQuery<
      { count: number } & AnyProcedure,
      string
    > & {
      data: {
        count: number;
        items: inferProcedureOutput<TData>;
      };
    };
  };
};

function usePagination<TData extends AnyQueryProcedure>(query){
  const [skip, take] = useSomethingThatManagesThis();

  const response = query.useQuery({
    skip,
    take,
  });
  
  return useMemo(() => ({
    items: response.data?.items,
    count: response.data?.count
  }), [response]);
}

但是我没有在响应中输入任何项目

function MyComponent() {
  const paginated = usePagination(api.user.list);
  
  const firstUserEmail = paginated.items?.[0].email; // paginated.items is any
}

我目前有一个变通方案,使用TRPC提供的类型推断实用程序,但我喜欢从查询中扣除这一点

export type RouterOutputs = inferRouterOutputs<AppRouter>;

function MyComponent() {
  const paginated = usePagination<RouterOutputs["user"]["list"]>(api.user.list);

  const firstUserEmail = paginated.items?.[0].email;
}
3phpmpom

3phpmpom1#

您可以使用TypeScript的泛型类型推断和条件类型。也从@trpc服务器导入ProcedureType
这里的ProcedureType type表示TRPC过程的类型(查询、变异等)。UseDatatableArgs类型将接受一个表示过程类型的泛型参数TData,它需要一个查询属性,该属性具有一个useQuery函数,该函数接受BaseInput作为输入,并返回一个ProcedureUseQuery类型和响应类型{ count: number } & TData。这是一份经过编辑的代码副本

import { ProcedureType } from "@trpc/server";
import { ProcedureUseQuery } from "trpc/react";

interface BaseInput {
  skip: number;
  take: number;
}

type UseDatatableArgs<TData extends ProcedureType> = {
  query?: {
    useQuery: (input: BaseInput) => ProcedureUseQuery<
      { count: number } & TData,
      string
    >;
  };
};

type PaginationResponse<TData extends ProcedureType> = {
  items: TData extends { data: { items: infer Items } } ? Items : never;
  count: number;
};

function usePagination<TData extends ProcedureType>(
  query: UseDatatableArgs<TData>["query"]
) {
  const [skip, take] = useSomethingThatManagesThis();

  const response = query?.useQuery({
    skip,
    take,
  });

  return useMemo(() => ({
    items: response?.data?.items,
    count: response?.data?.count
  }), [response]);
}

相关问题