question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

remove initTRPC double function call

See original GitHub issue

Describe the feature you’d like to request

I have always the feeling while editing /reading / writing the docs, (syntax) pain points arise. I was reading the migration guide and found this section

import { initTRPC } from '@trpc/server';

// Beware of the double `()()`
export const t = initTRPC()();

The comment already calls out this syntax is unfavourable (not obvious/ naturally) . I also dislike the syntax, because the function says nothing about what the input is for the first and second function. In the example below, why couldn’t the error formatter in the first one?.

export const t = initTRPC<{
  ctx: Context;
}>()({
  // Optional:
  transformer: superjson,
  // Optional:
  errorFormatter({ shape }) {
    return {
      ...shape,
      data: {
        ...shape.data,
      },
    };
  },
});

That you also need to put in the context type makes even more difficult

Describe the solution you’d like to see

In general, I think tRPC is missing a config server side. I propose two solutions as alternative:

// I looked into the source code  and the first function has zero params (?)
// TRPC exported function
const defineConfig = (config) => initTRPC()(config)

import { defineConfig, initTRPC } from "@trpc/server"; // defineConfig is more from the vue / vite landscape.
export const t = defineConfig() 

// for TRPC  the following names are maybe more correct:  
export const t = defineAppRouter(); 
export const t = defineBaseRouter(); 

After inspecting the source code I believe this syntax is possible. This would also improve the docs/ learning curve (one documentation page could explain all configurations of TRPC)

Option 2: change docs only (change trpcInner to a meaningful function name)

const trpcInner = initTRPC(); 
export const t =  trpcInner();

You could also take it one step further and create it as express app.

const trpc = initTRPC();

// custom methods to use on trpc 
trpc.onError();
trpc.use();

export const t =  trpc.create(); 

Desribe alternate solutions

current syntax

Additional information

Food for thought:

  • would it be nice to create a file convention like trpc.config.ts or trpc.router.ts ?

Question:

  • is the style of the new client, client.queries.getUsers() or client.getUsers.query()?

👨‍👧‍👦 Contributing

  • 🙋‍♂️ Yes, I’d be down to file a PR implementing this feature!

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
mmkalcommented, Aug 30, 2022

Nice - yes I can open a pr. Have been looking for a chance to make a v10 change about this size.

3reactions
mmkalcommented, Aug 30, 2022

Reopening this because I think there’s further discussion to be had, and I don’t want it to get lost on a closed thread (not implying it was closed improperly, I just have something I want to add).

@sachinraja @KATT what about naming two functions in some kind of logical way so there isn’t this big gulf between users and implementers. Anyone new looking at initTRPC()() is going to get intimidated and probably put off. What about something like:

// initTRPC.ts
export interface TRPCBuilder<TParams extends Partial<InitGenerics>> {
    configure: <TNewParams extends TParams>() => TRPCBuilder<TNewParams>
    builder: <
        TOptions extends Partial<InitOptions<{
            ctx: TParams['ctx'] extends undefined ? {} : NonNullable<TParams['ctx']>;
            meta: TParams['meta'] extends undefined ? {} : NonNullable<TParams['meta']>;
        }>>
    >(options?: ValidateShape<TOptions, Partial<InitOptions<{
        ctx: TParams['ctx'] extends undefined ? {} : NonNullable<TParams['ctx']>;
        meta: TParams['meta'] extends undefined ? {} : NonNullable<TParams['meta']>;
    }>>> | undefined) =>  /* same as existing final return type of initTRPC */
}

export const trpc: TRPCBuilder<{}>

Usage:

import {trpc} from '@trpc/server'

const t = trpc.builder()

export const whatever = t.procedure
  .input(z.object({ foo: z.string() })
  .query(({ input }) => [input.foo])

Or with ctx/meta options:

import {trpc} from '@trpc/server'

const t = trpc.configure<{ ctx: { abc: number } }>().builder()

export const whatever = t.procedure
  .input(z.object({ foo: z.string() })
  .query(({ input, ctx }) => [input.foo, ctx.abc])

Not sure about the naming of either .configure() or .builder().

Another option would be just to have two methods .withContext<{ abc: number }>() and .withMeta<{ xyz: string }>() which would add ctx and meta generics, respectively.

.builder() might not be the best name if t shouldn’t be considered a builder. (If it isn’t - what is it? I think it’s important that it has some kind of English-language name, so people can communicate about it properly, since it’s an important part of the design - in general I think we should show things we love them by naming them).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Two sets of parentheses after function call - javascript
It means that the first function ( $filter ) returns another function and then that returned function is called immediately. For Example:
Read more >
Quickstart | tRPC
Learn how to quickly get started and setup tRPC.
Read more >
Getting started | tRPC-SvelteKit - GitHub Pages
The trpc-sveltekit package exports two functions: createTRPCHandle and createTRPCClient . The former is used in your SvelteKit app hooks, the latter is used...
Read more >
Why do we call the functions without parentheses ie '()'?
We created two functions: passwordEvent() and confirmPasswordEvent(). Normally when you call a function, you have to include parentheses ...
Read more >
How to Setup tRPC API Server & Client with Next.js and Prisma
To do this, we'll evoke the initTRPC method, append the Context we created above, call the .create() method and pass superjson as the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found