Я использую tRPC в проекте с уже существующими вызовами API и хотел бы обернуть функцию useQuery в отдельную оболочку, но мне сложно правильно определить типы TypeScript.
Вот как выглядит идеальный результат. Вместо следующего кода:
const query = trpc.myendpoint.useQuery({ foo: 'bar' });
... Я хотел бы написать это:
const query = useCustomHook(trpc.myendpoint, { foo: 'bar' });
Часть JavaScript легко реализовать, но мне трудно правильно определить типы TypeScript. Я хочу, чтобы useCustomHook
возвращал правильный тип данных. Вот мой any
-хак, который технически работает, но не дает подсказок по типу:
function useCustomHook(obj: any, queryData: any) {
// ... Here I have some code related to my old code, which is why I need the custom hook
return obj.useQuery(queryData);
}
Я уже пробовал приведенный ниже код, а также пробовал выводить типы, но не получилось. Это были некоторые из моих подходов, в которых я уже не знал, как правильно набирать queryData
:
// Approach using the trpc object
type TrpcProcedure1 = (typeof trpc)[keyof typeof trpc];
function useCustomHook<T extends TrpcProcedure>(obj: TrpcProcedure1, queryData: ???) {}
// Error when calling obj.useQuery:
// Property 'useQuery' does not exist on type 'TrpcProcedure'.
// Approach going via AppRouter['_def']['procedures']
type TrpcProcedure2 = (typeof trpc)[keyof AppRouter['_def']['procedures']];
function useCustomHook<T extends TrpcProcedure>(obj: TrpcProcedure2, queryData: ???) {}
// Error when calling obj.useQuery:
// This expression is not callable. Each member of the union type 'ProcedureUseQuery<...>' has signatures, but none of those signatures are compatible with each other
К сожалению, оба привели к сообщениям об ошибках, как написано.
🤔 А знаете ли вы, что...
JavaScript поддерживает асинхронное программирование с использованием промисов и асинхронных функций.
Мне удалось заставить его работать (благодаря помощи дискорда tRPC):
import { DecorateProcedure, UseTRPCQueryResult } from "@trpc/react-query/shared";
import { AnyQueryProcedure, inferProcedureInput, inferProcedureOutput } from "@trpc/server";
import { TRPCClientErrorLike } from "@trpc/client";
function useCustomHook<QueryProcedure extends AnyQueryProcedure, U, V extends string>(
proc: DecorateProcedure<QueryProcedure, U, V>,
params: inferProcedureInput<QueryProcedure>
): UseTRPCQueryResult<inferProcedureOutput<QueryProcedure>, TRPCClientErrorLike<QueryProcedure>> {
// custom code...
return proc.useQuery(params);
}
Используя этот код, входные и выходные данные печатаются правильно.
DecorateProcedure<QueryProcedure, U, V>
— тип процедуры, где QueryProcedure extends AnyQueryProcedure
. Затем входные параметры можно вывести с помощью inferProcedureInput<QueryProcedure>
. Аналогично, тип вывода можно определить с помощью inferProcedureOutput<QueryProcedure>
, а затем обернуть в UseTRPCQueryResult
.