ronantakizawa/codereview-bench huggingface dataset:
Repository: trpc/trpc
File: packages/client/src/links/httpBatchStreamLink.ts (TypeScript)

Code before:
import { NonEmptyArray } from '../internals/types';
import {
  createHTTPBatchLink,
  RequesterFn,
} from './internals/createHTTPBatchLink';
import { streamingJsonHttpRequester } from './internals/parseJSONStream';
import { Operation } from './types';

const streamRequester: RequesterFn = (requesterOpts) => {
  const textDecoder =
    requesterOpts.opts.textDecoder || new global.TextDecoder();
  return (batchOps, unitResolver) => {
    const path = batchOps.map((op) => op.path).join(',');
    const inputs = batchOps.map((op) => op.input);

    const { cancel, promise } = streamingJsonHttpRequester(
      {
        ...requesterOpts,
        textDecoder,
        path,
        inputs,
        headers() {
          if (!requesterOpts.opts.headers) {
            return {};
          }
          if (typeof requesterOpts.opts.headers === 'function') {
            return requesterOpts.opts.headers({
              opList: batchOps as NonEmptyArray<Operation>,
            });
          }
          return requesterOpts.opts.headers;
        },
      },
      (index, res) => unitResolver(index, res),
    );

Review comment (bug):
I'd use a helper like we do for `fetch` https://github.com/trpc/trpc/blob/df2d2fb3cbbe5736ee6e6594d7b2bd01bd6c112d/packages/client/src/getFetch.ts#L12-L28 so it's more clear what went wrong in case this fails.

Code after:
import { NonEmptyArray } from '../internals/types';
import { HTTPBatchStreamLinkOptions } from './HTTPBatchStreamLinkOptions';
import {
  createHTTPBatchLink,
  RequesterFn,
} from './internals/createHTTPBatchLink';
import { getTextDecoder } from './internals/getTextDecoder';
import { streamingJsonHttpRequester } from './internals/parseJSONStream';
import { Operation } from './types';

const streamRequester: RequesterFn<HTTPBatchStreamLinkOptions> = (
  requesterOpts,
) => {
  const textDecoder = getTextDecoder(requesterOpts.opts.textDecoder);
  return (batchOps, unitResolver) => {
    const path = batchOps.map((op) => op.path).join(',');
    const inputs = batchOps.map((op) => op.input);

    const { cancel, promise } = streamingJsonHttpRequester(
      {
        ...requesterOpts,
        textDecoder,
        path,
        inputs,
        headers() {
          if (!requesterOpts.opts.headers) {
            return {};
          }
          if (typeof requesterOpts.opts.headers === 'function') {
            return requesterOpts.opts.headers({
              opList: batchOps as NonEmptyArray<Operation>,
            });
          }
          return requesterOpts.opts.headers;
        },
Repository: trpc/trpc
File: packages/client/src/links/HTTPBatchLinkOptions.ts (TypeScript)

Code before:
import { NonEmptyArray } from '../internals/types';
import { HTTPLinkBaseOptions } from './internals/httpUtils';
import { TextDecoderEsque } from './internals/streamingUtils';
import { HTTPHeaders, Operation } from './types';

export interface HTTPBatchLinkOptions extends HTTPLinkBaseOptions {
  maxURLLength?: number;
  /**
   * Headers to be set on outgoing requests or a callback that of said headers
   * @link http://trpc.io/docs/client/headers
   */
  headers?:
    | HTTPHeaders
    | ((opts: {
        opList: NonEmptyArray<Operation>;
      }) => HTTPHeaders | Promise<HTTPHeaders>);

  /**
   * Used for `httpBatchStreamLink`. Will default to the webAPI `TextDecoder`,
   * but you can use this option if your client runtime doesn't provide it.
   */
  textDecoder?: TextDecoderEsque;
}
/**
 * @alias HttpBatchLinkOptions
 * @deprecated use `HTTPBatchLinkOptions` instead
 */
export interface HttpBatchLinkOptions extends HTTPBatchLinkOptions {}


Review comment (performance):
I would much prefer if this was part of **only** the stream options, so we'd have a `HTTPBatchStreamLinkOptions`

Code after:
import { NonEmptyArray } from '../internals/types';
import { HTTPLinkBaseOptions } from './internals/httpUtils';
import { HTTPHeaders, Operation } from './types';

export interface HTTPBatchLinkOptions extends HTTPLinkBaseOptions {
  maxURLLength?: number;
  /**
   * Headers to be set on outgoing requests or a callback that of said headers
   * @link http://trpc.io/docs/client/headers
   */
  headers?:
    | HTTPHeaders
    | ((opts: {
        opList: NonEmptyArray<Operation>;
      }) => HTTPHeaders | Promise<HTTPHeaders>);
}
/**
 * @alias HttpBatchLinkOptions
 * @deprecated use `HTTPBatchLinkOptions` instead
 */
export interface HttpBatchLinkOptions extends HTTPBatchLinkOptions {}
Repository: trpc/trpc
File: packages/tests/server/regression/issue-4527-nested-middleware-root-context.test.ts (TypeScript)

Code before:
    if (!ctx.apiKey) {
      throw new TRPCError({ code: 'UNAUTHORIZED' });
    }

    return next({ ctx: { apiKey: ctx.apiKey } });
  });

  const formDataMiddleware = t.middleware(async ({ next }) => {
    return next({ rawInput: new FormData() });
  });

  const protectedApiProcedure = t.procedure.use(enforceApiKey);
  const protectedApiFormDataProcedure = t.procedure
    .use(formDataMiddleware)
    .use(enforceApiKey);

  // root context -> enforceApiKey -> formDataMiddleware
  protectedApiProcedure
    .use(formDataMiddleware)
    .input(
      z.object({
        somehash: z.string(),
      }),
    )
    .query(async (opts) => {
      expectTypeOf<string>(opts.ctx.apiKey);

      return { status: 'ok' };
    });

  // root context -> formDataMiddleware -> enforceApiKey
  protectedApiFormDataProcedure
    .input(
      z.object({
        somehash: z.string(),
      }),
    )
    .query(async (opts) => {
      expectTypeOf<string>(opts.ctx.apiKey);

      return { status: 'ok' };
    });
});


Review comment (suggestion):
```suggestion
      expectTypeOf<Request | undefined>(opts.ctx.req);

```

for good measure 🤷🏼 

Code after:
    if (!ctx.apiKey) {
      throw new TRPCError({ code: 'UNAUTHORIZED' });
    }

    return next({ ctx: { apiKey: ctx.apiKey } });
  });

  const formDataMiddleware = t.middleware(async ({ next }) => {
    return next({ rawInput: new FormData() });
  });

  // root context -> enforceApiKey -> formDataMiddleware
  t.procedure
    .use(enforceApiKey)
    .use(formDataMiddleware)
    .input(
      z.object({
        somehash: z.string(),
      }),
    )
    .query(async (opts) => {
      expectTypeOf<{
        req?: Request;
        apiKey: string;
      }>(opts.ctx);

      return { status: 'ok' };
    });

  // root context -> formDataMiddleware -> enforceApiKey
  t.procedure
    .use(formDataMiddleware)
    .use(enforceApiKey)
    .input(
      z.object({
        somehash: z.string(),
      }),
    )
    .query(async (opts) => {
      expectTypeOf<{
        req?: Request;
        apiKey: string;
      }>(opts.ctx);

      return { status: 'ok' };
    });
});
Repository: trpc/trpc
File: packages/tests/server/regression/issue-4527-nested-middleware-root-context.test.ts (TypeScript)

Code before:
    .use(formDataMiddleware)
    .input(
      z.object({
        somehash: z.string(),
      }),
    )
    .query(async (opts) => {
      expectTypeOf<string>(opts.ctx.apiKey);

      return { status: 'ok' };
    });

  // root context -> formDataMiddleware -> enforceApiKey
  protectedApiFormDataProcedure
    .input(
      z.object({
        somehash: z.string(),
      }),
    )
    .query(async (opts) => {
      expectTypeOf<string>(opts.ctx.apiKey);

      return { status: 'ok' };
    });
});


Review comment (suggestion):
```suggestion
      expectTypeOf<Request | undefined>(opts.ctx.req);

```

for good measure 🤷🏼 

Code after:
      }),
    )
    .query(async (opts) => {
      expectTypeOf<{
        req?: Request;
        apiKey: string;
      }>(opts.ctx);

      return { status: 'ok' };
    });

  // root context -> formDataMiddleware -> enforceApiKey
  t.procedure
    .use(formDataMiddleware)
    .use(enforceApiKey)
    .input(
      z.object({
        somehash: z.string(),
      }),
    )
    .query(async (opts) => {
      expectTypeOf<{
        req?: Request;
        apiKey: string;
      }>(opts.ctx);

      return { status: 'ok' };
    });
});
Repository: trpc/trpc
File: packages/react-query/src/server/index.ts (TypeScript)

Code before:
export { createServerSideHelpers } from './ssgProxy';
export type {
  /**
   * @deprecated this exported type is will be removed in the next major version
   */
  CreateServerSideHelpersOptions as CreateSSGHelpersOptions,
} from './types';

export type { DecoratedProcedureSSGRecord } from './ssgProxy';


Review comment (suggestion):
```suggestion
   * @deprecated this exported is planned to be removed in the next major version
```

Code after:
export { createServerSideHelpers } from './ssgProxy';
export type {
  /**
   * @deprecated this exported is planned to be removed in the next major version
   */
  CreateServerSideHelpersOptions as CreateSSGHelpersOptions,
} from './types';

export type { DecoratedProcedureSSGRecord } from './ssgProxy';
Repository: trpc/trpc
File: packages/tests/server/regression/issue-4750-no-cancel.test.ts (TypeScript)

Code before:

  expect(abortController.signal.aborted).toBe(false);

  await close();
});

test('httpBatchLink', async () => {
  const abortController = new AbortController();

  const { close, proxy } = routerToServerAndClientNew(router, {
    client({ httpUrl }) {
      return {
        links: [httpBatchLink({ url: httpUrl })],
      };
    },
  });

  await proxy.q
    .query(undefined, {
      signal: abortController.signal,
    })
    .catch(() => {
      /// ..
    });

  expect(abortController.signal).toBe(false);

  await close();
});


Review comment (suggestion):
I believe you wanted to assert on `.aborted` here? If so, it passes just fine when changed.

Code after:

test('httpLink', async () => {
  const spy = abortControllerSpy();
  const { close, proxy } = routerToServerAndClientNew(router, {
    client({ httpUrl }) {
      return {
        links: [httpLink({ url: httpUrl, AbortController: spy.AC })],
      };
    },
  });

  await proxy.q.query(undefined).catch(() => {
    /// ..
  });

  expect(spy.instanceSpy).toHaveBeenCalledTimes(1);
  expect(spy.abortSpy).toHaveBeenCalledTimes(0);

  await close();
});

test('httpBatchLink', async () => {
  const spy = abortControllerSpy();
  const { close, proxy } = routerToServerAndClientNew(router, {
    client({ httpUrl }) {
      return {
        links: [httpBatchLink({ url: httpUrl, AbortController: spy.AC })],
      };
    },
  });

  await proxy.q.query(undefined).catch(() => {
    /// ..
  });

  expect(spy.instanceSpy).toHaveBeenCalledTimes(1);
  expect(spy.abortSpy).toHaveBeenCalledTimes(0);

  await close();
});
Repository: trpc/trpc
File: packages/client/src/links/internals/httpUtils.ts (TypeScript)

Code before:

export function httpRequest(
  opts: HTTPRequestOptions,
): PromiseAndCancel<HTTPResult> {
  const ac = opts.AbortController ? new opts.AbortController() : null;
  const meta = {} as HTTPResult['meta'];

  const promise = new Promise<HTTPResult>((resolve, reject) => {
    fetchHTTPResponse(opts, ac)
      .then((_res) => {
        meta.response = _res;
        return _res.json();
      })
      .then((json) => {
        meta.responseJSON = json;
        resolve({
          json: json as TRPCResponse,
          meta,
        });
      })
      .catch((err) => {
        reject(TRPCClientError.from(err, { meta }));
      });
  });
  const cancel = () => {
    ac?.abort();
  };
  return { promise, cancel };
}


Review comment (suggestion):
You can also use `.finally(() => { done = true; });` to have everything in one place.

Code after:

export function httpRequest(
  opts: HTTPRequestOptions,
): PromiseAndCancel<HTTPResult> {
  const ac = opts.AbortController ? new opts.AbortController() : null;
  const meta = {} as HTTPResult['meta'];

  let done = false;
  const promise = new Promise<HTTPResult>((resolve, reject) => {
    fetchHTTPResponse(opts, ac)
      .then((_res) => {
        meta.response = _res;
        done = true;
        return _res.json();
      })
      .then((json) => {
        meta.responseJSON = json;
        resolve({
          json: json as TRPCResponse,
          meta,
        });
      })
      .catch((err) => {
        done = true;
        reject(TRPCClientError.from(err, { meta }));
      });
  });
  const cancel = () => {
    if (!done) {
      ac?.abort();
    }
  };
  return { promise, cancel };
}
Repository: trpc/trpc
File: packages/react-query/src/server/ssgProxy.ts (TypeScript)

Code before:
  ClientDataTransformerOptions,
  Filter,
  inferProcedureInput,
  inferRouterContext,
  Maybe,
  ProtectedIntersection,
} from '@trpc/server';
import {
  createFlatProxy,
  createRecursiveProxy,
  inferTransformedProcedureOutput,
} from '@trpc/server/shared';
import { getQueryKeyInternal } from '../internals/getQueryKey';
import {
  CreateTRPCReactQueryClientConfig,
  ExtractCursorType,
  getQueryClient,
  getQueryType,
  TRPCFetchInfiniteQueryOptions,
  TRPCFetchQueryOptions,
} from '../shared';

interface CreateSSGHelpersInternal<TRouter extends AnyRouter> {
  router: TRouter;
  ctx: inferRouterContext<TRouter>;
  transformer?: ClientDataTransformerOptions;
}

interface CreateSSGHelpersExternal<TRouter extends AnyRouter> {
  client: inferRouterClient<TRouter> | TRPCUntypedClient<TRouter>;
}

type CreateServerSideHelpersOptions<TRouter extends AnyRouter> =
  CreateTRPCReactQueryClientConfig &
    (CreateSSGHelpersExternal<TRouter> | CreateSSGHelpersInternal<TRouter>);

type DecorateProcedure<
  TConfig extends AnyRootConfig,
  TProcedure extends AnyProcedure,
> = {
  /**
   * @link https://tanstack.com/query/v5/docs/react/guides/prefetching
   */
  fetch(
    input: inferProcedureInput<TProcedure>,
    opts?: TRPCFetchQueryOptions<
      inferTransformedProcedureOutput<TConfig, TProcedure>,
      TRPCClientError<TConfig>
    >,
  ): Promise<inferTransformedProcedureOutput<TConfig, TProcedure>>;


Review comment (suggestion):
I'm not completely sure of the differences between all the different DataTransformer types to be fair, so this should probably be validated @KATT 

Code after:
  DataTransformerOptions,
  Filter,
  inferProcedureInput,
  inferRouterContext,
  Maybe,
  ProtectedIntersection,
} from '@trpc/server';
import {
  createFlatProxy,
  createRecursiveProxy,
  inferTransformedProcedureOutput,
} from '@trpc/server/shared';
import { getQueryKeyInternal } from '../internals/getQueryKey';
import {
  CreateTRPCReactQueryClientConfig,
  ExtractCursorType,
  getQueryClient,
  getQueryType,
  TRPCFetchInfiniteQueryOptions,
  TRPCFetchQueryOptions,
} from '../shared';

interface CreateSSGHelpersInternal<TRouter extends AnyRouter> {
  router: TRouter;
  ctx: inferRouterContext<TRouter>;
  transformer?: DataTransformerOptions;
}

interface CreateSSGHelpersExternal<TRouter extends AnyRouter> {
  client: inferRouterClient<TRouter> | TRPCUntypedClient<TRouter>;
}

type CreateServerSideHelpersOptions<TRouter extends AnyRouter> =
  CreateTRPCReactQueryClientConfig &
    (CreateSSGHelpersExternal<TRouter> | CreateSSGHelpersInternal<TRouter>);

type DecorateProcedure<
  TConfig extends AnyRootConfig,
  TProcedure extends AnyProcedure,
> = {
  /**
   * @link https://tanstack.com/query/v5/docs/react/guides/prefetching
   */
  fetch(
    input: inferProcedureInput<TProcedure>,
    opts?: TRPCFetchQueryOptions<
      inferTransformedProcedureOutput<TConfig, TProcedure>,
      TRPCClientError<TConfig>
    >,
  ): Promise<inferTransformedProcedureOutput<TConfig, TProcedure>>;
Repository: trpc/trpc
File: packages/server/src/adapters/standalone.ts (TypeScript)

Code before:
  NodeHTTPCreateContextFnOptions,
  NodeHTTPHandlerOptions,
} from './node-http';
import { nodeHTTPRequestHandler } from './node-http';

export type CreateHTTPHandlerOptions<TRouter extends AnyRouter> =
  NodeHTTPHandlerOptions<TRouter, http.IncomingMessage, http.ServerResponse>;

export type CreateHTTPContextOptions = NodeHTTPCreateContextFnOptions<
  http.IncomingMessage,
  http.ServerResponse
>;

export function createHTTPHandler<TRouter extends AnyRouter>(
  opts: CreateHTTPHandlerOptions<TRouter>,
) {
  return async (req: http.IncomingMessage, res: http.ServerResponse) => {
    const url = toUrl(req.url!);

    // get procedure path and remove the leading slash
    // /procedure -> procedure
    const path = url.pathname.slice(1);

    await nodeHTTPRequestHandler({
      // FIXME: no typecasting should be needed here
      ...opts,
      req,
      res,
      path,
    });
  };
}

export function createHTTPServer<TRouter extends AnyRouter>(
  opts: CreateHTTPHandlerOptions<TRouter>,
) {
  const handler = createHTTPHandler(opts);
  const server = http.createServer((req, res) => handler(req, res));

  return {
    server,
    listen: (port?: number, hostname?: string) => {
      server.listen(port, hostname);
      const actualPort =
        port === 0 ? ((server.address() as any).port as number) : port;

      return {
        port: actualPort,
      };
    },
  };

Review comment (suggestion):
```suggestion
      ...(opts as CreateHTTPHandlerOptions<AnyRouter>),
```

Code after:
  NodeHTTPCreateContextFnOptions,
  NodeHTTPHandlerOptions,
} from './node-http';
import { nodeHTTPRequestHandler } from './node-http';

export type CreateHTTPHandlerOptions<TRouter extends AnyRouter> =
  NodeHTTPHandlerOptions<TRouter, http.IncomingMessage, http.ServerResponse>;

export type CreateHTTPContextOptions = NodeHTTPCreateContextFnOptions<
  http.IncomingMessage,
  http.ServerResponse
>;

export function createHTTPHandler<TRouter extends AnyRouter>(
  opts: CreateHTTPHandlerOptions<TRouter>,
) {
  return async (req: http.IncomingMessage, res: http.ServerResponse) => {
    const url = toURL(req.url!);

    // get procedure path and remove the leading slash
    // /procedure -> procedure
    const path = url.pathname.slice(1);

    await nodeHTTPRequestHandler({
      // FIXME: no typecasting should be needed here
      ...(opts as CreateHTTPHandlerOptions<AnyRouter>),
      req,
      res,
      path,
    });
  };
}

export function createHTTPServer<TRouter extends AnyRouter>(
  opts: CreateHTTPHandlerOptions<TRouter>,
) {
  const handler = createHTTPHandler(opts);
  const server = http.createServer((req, res) => handler(req, res));

  return {
    server,
    listen: (port?: number, hostname?: string) => {
      server.listen(port, hostname);
      const actualPort =
        port === 0 ? ((server.address() as any).port as number) : port;

      return {
        port: actualPort,
      };
    },
  };
Repository: trpc/trpc
File: packages/server/src/unstable-core-do-not-import/procedureBuilder.ts (TypeScript)

Code before:
   * Combine two procedure builders
   */
  unstable_concat<
    $Context,
    $Meta,
    $ContextOverrides,
    $InputIn,
    $InputOut,
    $OutputIn,
    $OutputOut,
  >(
    builder: Overwrite<TContext, TContextOverrides> extends $Context
      ? TMeta extends $Meta
        ? ProcedureBuilder<
            $Context,
            $Meta,
            $ContextOverrides,
            $InputIn,
            $InputOut,
            $OutputIn,
            $OutputOut
          >
        : TypeError<'Meta mismatch'>
      : TypeError<'Context mismatch'>,
  ): ProcedureBuilder<
    TContext,
    TMeta,
    Overwrite<TContextOverrides, $ContextOverrides>,
    Overwrite<TInputIn, $InputIn>,
    Overwrite<TInputIn, $InputOut>,
    Overwrite<TOutputIn, $OutputIn>,
    Overwrite<TOutputOut, $OutputOut>
  >;
  /**
   * Query procedure
   * @link https://trpc.io/docs/v11/concepts#vocabulary
   */
  query<$Output>(
    resolver: ProcedureResolver<
      TContext,
      TMeta,
      TContextOverrides,
      TInputOut,
      TOutputIn,
      $Output
    >,
  ): QueryProcedure<{
    input: DefaultValue<TInputIn, void>;
    output: DefaultValue<TOutputOut, $Output>;
  }>;


Review comment (suggestion):
ideally we should do this for `InputIn/Out` too similar to we do in the `.input()`-fn but this if safe enough I reckon

Code after:

  /**
   * Combine two procedure builders
   */
  unstable_concat<
    $Context,
    $Meta,
    $ContextOverrides,
    $InputIn,
    $InputOut,
    $OutputIn,
    $OutputOut,
  >(
    builder: Overwrite<TContext, TContextOverrides> extends $Context
      ? TMeta extends $Meta
        ? ProcedureBuilder<
            $Context,
            $Meta,
            $ContextOverrides,
            $InputIn,
            $InputOut,
            $OutputIn,
            $OutputOut
          >
        : TypeError<'Meta mismatch'>
      : TypeError<'Context mismatch'>,
  ): ProcedureBuilder<
    TContext,
    TMeta,
    Overwrite<TContextOverrides, $ContextOverrides>,
    IntersectIfDefined<TInputIn, $InputIn>,
    IntersectIfDefined<TInputIn, $InputOut>,
    IntersectIfDefined<TOutputIn, $OutputIn>,
    IntersectIfDefined<TOutputOut, $OutputOut>
  >;
  /**
   * Query procedure
   * @link https://trpc.io/docs/v11/concepts#vocabulary
   */
  query<$Output>(
    resolver: ProcedureResolver<
      TContext,
      TMeta,
      TContextOverrides,
      TInputOut,
      TOutputIn,
      $Output
    >,
  ): QueryProcedure<{
    input: DefaultValue<TInputIn, void>;
    output: DefaultValue<TOutputOut, $Output>;
Repository: trpc/trpc
File: packages/tests/server/react/useQuery.test.tsx (TypeScript)

Code before:
      <>
        <button
          data-testid="fetchMore"
          onClick={() => {
            query1.fetchNextPage();
          }}
        >
          Fetch more
        </button>
        <button
          data-testid="prefetch"
          onClick={async () => {
            const fetched = await trpcContext.post.list.fetchInfinite({}, {});
            expectTypeOf<{
              pages: { items: typeof fixtureData; next?: number | undefined }[];
              pageParams: (number | null)[];
            }>(fetched);
            expect(
              fetched.pageParams.some((p) => typeof p === 'undefined'),
            ).toBeFalsy();
          }}
        >
          Fetch
        </button>
        <pre>{JSON.stringify(query1.data ?? 'n/a', null, 4)}</pre>
      </>
    );
  }

  const utils = render(
    <App>
      <MyComponent />
    </App>,
  );

  await waitFor(() => {
    expect(utils.container).toHaveTextContent(`[ "1" ]`);
    expect(utils.container).toHaveTextContent(`null`);
    expect(utils.container).not.toHaveTextContent(`undefined`);
  });
  await userEvent.click(utils.getByTestId('fetchMore'));

  await waitFor(() => {
    expect(utils.container).toHaveTextContent(`[ "1" ]`);
    expect(utils.container).toHaveTextContent(`[ "2" ]`);
  });
});

test('useInfiniteQuery() initialCursor', async () => {
  const { App, client } = ctx;
  function MyComponent() {

Review comment (suggestion):
I can write exactly the same test for just useQuery(skipToken), it will have the exact same type, because query can be populated imperatively. I think it's redundant, but let me know if you would like to have it

Code after:
  });

  test('data type with initialData', () => {
    const expectation = expectTypeOf(() =>
      ctx.client.post.byId.useQuery(
        { id: '1' },
        {
          initialData: '__result',
        },
      ),
    ).returns;

    expectation.toMatchTypeOf<{ data: '__result' }>();
    expectation.not.toMatchTypeOf<{ data: undefined }>();
  });

  test('data type with conditional skipToken', () => {
    const expectation = expectTypeOf(() =>
      ctx.client.post.byId.useQuery(
        Math.random() > 0.5 ? skipToken : { id: '1' },
      ),
    ).returns;

    expectation.toMatchTypeOf<{ data: '__result' | undefined }>();
    expectation.not.toMatchTypeOf<{ data: undefined }>();
  });
});

test('useInfiniteQuery()', async () => {
  const { App, client } = ctx;
  function MyComponent() {
    const trpcContext = client.useContext();
    const query1 = client.post.list.useInfiniteQuery(
      {},
      {
        getNextPageParam(lastPage) {
          return lastPage.next;
        },
      },
    );
    expect(query1.trpc.path).toBe('post.list');

    if (!query1.data) {
      return <>...</>;
    }

    expectTypeOf<
      InfiniteData<
        {
          items: typeof fixtureData;
          next?: number | undefined;