Katzius
Katzius14mo ago

I want to create a wrapper for TRPC.init but I can't seem to get the context type correct.

I want to get wrap trpc.init
3 Replies
Katzius
KatziusOP14mo ago
create-context.ts
import {inferAsyncReturnType} from '@trpc/server'
import type {
CreateFastifyContextOptions,
FastifyTRPCPluginOptions,
// eslint-disable-next-line
} from '@trpc/server/adapters/fastify'

/**
* Defines your inner context shape.
* Add fields here that the inner context brings.
*/
export interface CreateInnerContextOptions extends Partial<CreateFastifyContextOptions> {}

export function createContext(config: Partial<FastifyTRPCPluginOptions<any>>) {
return (outerOptions: CreateFastifyContextOptions) => {
return createInternalContext((innerOptions) => {
if (!outerOptions?.req || !outerOptions?.res) {
return innerOptions
}
return {
...innerOptions,
...config?.trpcOptions?.createContext?.({
req: outerOptions.req,
res: outerOptions.res,
}),
}
}, outerOptions)
}
}

/**
* Outer context. Used in the routers and will e.g. bring `req` & `res` to the context as "not `undefined`".
*
* @see https://trpc.io/docs/context#inner-and-outer-context
*/
async function createInternalContext<T>(
createContextInner: (opts?: CreateInnerContextOptions) => T,
opts: CreateFastifyContextOptions,
) {
const contextInner = createContextInner()
return {
...contextInner,
req: opts.req,
res: opts.res,
}
}

export type Context<T> = inferAsyncReturnType<(opts: T) => Awaited<typeof createContext>>
import {inferAsyncReturnType} from '@trpc/server'
import type {
CreateFastifyContextOptions,
FastifyTRPCPluginOptions,
// eslint-disable-next-line
} from '@trpc/server/adapters/fastify'

/**
* Defines your inner context shape.
* Add fields here that the inner context brings.
*/
export interface CreateInnerContextOptions extends Partial<CreateFastifyContextOptions> {}

export function createContext(config: Partial<FastifyTRPCPluginOptions<any>>) {
return (outerOptions: CreateFastifyContextOptions) => {
return createInternalContext((innerOptions) => {
if (!outerOptions?.req || !outerOptions?.res) {
return innerOptions
}
return {
...innerOptions,
...config?.trpcOptions?.createContext?.({
req: outerOptions.req,
res: outerOptions.res,
}),
}
}, outerOptions)
}
}

/**
* Outer context. Used in the routers and will e.g. bring `req` & `res` to the context as "not `undefined`".
*
* @see https://trpc.io/docs/context#inner-and-outer-context
*/
async function createInternalContext<T>(
createContextInner: (opts?: CreateInnerContextOptions) => T,
opts: CreateFastifyContextOptions,
) {
const contextInner = createContextInner()
return {
...contextInner,
req: opts.req,
res: opts.res,
}
}

export type Context<T> = inferAsyncReturnType<(opts: T) => Awaited<typeof createContext>>
and I want to do:
function makeTRPC<T>() {
const t = initTRPC.context<Context<T>>().create({
errorFormatter({shape}) {
return shape
},
})
return t
}
function makeTRPC<T>() {
const t = initTRPC.context<Context<T>>().create({
errorFormatter({shape}) {
return shape
},
})
return t
}
but when I do:
const t = makeTRPC<{test: string}>()
const t = makeTRPC<{test: string}>()
t.context is of type {} when I do that 😦
Sandvich
Sandvich14mo ago
You do Awaited<typeof createContext> but createContext isn't async so that doesn't do anything. I'd recommend just starting over with initTRPC.context<{test: string}>.create(...); and keep building up slowly to the more complex type you have until you find the error you made
Katzius
KatziusOP14mo ago
it works, the problem is with the generic type makeTRPC<T> always resolves to {} even without the Awaited, it results in the same output thanks for the answer by th eway was able to resolve it using type inference: type LocalContext<T> = inferAsyncReturnType<typeof createInternalContext<T>> export type Context<T> = T extends infer R ? LocalContext<R> : never