Оберните useQuery tRPC в специальный хук с правильными типами TypeScript

Я использую 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 поддерживает асинхронное программирование с использованием промисов и асинхронных функций.


1
51
1

Ответ:

Решено

Мне удалось заставить его работать (благодаря помощи дискорда 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.