Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/contract/src/builder.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('ContractBuilder', () => {
type MetaDef = { meta1?: string, meta2?: number }

expectTypeOf(builder.$meta<MetaDef>({ meta1: 'value' })).toEqualTypeOf<
ContractBuilder<typeof inputSchema, typeof outputSchema, typeof baseErrorMap, MetaDef>
ContractBuilder<typeof inputSchema, typeof outputSchema, typeof baseErrorMap, MetaDef & Record<never, never>>
>()

// @ts-expect-error - invalid initial meta
Expand Down
6 changes: 5 additions & 1 deletion packages/contract/src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ export class ContractBuilder<
*/
$meta<U extends Meta>(
initialMeta: U,
): ContractBuilder<TInputSchema, TOutputSchema, TErrorMap, U> {
): ContractBuilder<TInputSchema, TOutputSchema, TErrorMap, U & Record<never, never>> {
/**
* We need `& Record<never, never>` to deal with `has no properties in common with type` error
*/

return new ContractBuilder({
...this['~orpc'],
meta: initialMeta,
Expand Down
6 changes: 3 additions & 3 deletions packages/server/src/builder.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ describe('Builder', () => {
expectTypeOf(
builder.middleware(({ context, next, path, procedure, errors, signal }, input, output) => {
expectTypeOf(input).toEqualTypeOf<unknown>()
expectTypeOf(context).toEqualTypeOf<CurrentContext>()
expectTypeOf(context).toEqualTypeOf<InitialContext>()
expectTypeOf(path).toEqualTypeOf<readonly string[]>()
expectTypeOf(procedure).toEqualTypeOf<
Procedure<Context, Context, AnySchema, AnySchema, ErrorMap, BaseMeta>
Expand All @@ -173,7 +173,7 @@ describe('Builder', () => {
})
}),
).toEqualTypeOf<
DecoratedMiddleware<CurrentContext, { extra: boolean }, unknown, any, ORPCErrorConstructorMap<any>, BaseMeta>
DecoratedMiddleware<InitialContext, { extra: boolean }, unknown, any, ORPCErrorConstructorMap<any>, BaseMeta>
>()

// @ts-expect-error --- conflict context
Expand All @@ -184,7 +184,7 @@ describe('Builder', () => {
expectTypeOf(
builder.middleware(({ next }, input: 'input', output: MiddlewareOutputFn<'output'>) => next()),
).toEqualTypeOf<
DecoratedMiddleware<CurrentContext, Record<never, never>, 'input', 'output', ORPCErrorConstructorMap<any>, BaseMeta>
DecoratedMiddleware<InitialContext, Record<never, never>, 'input', 'output', ORPCErrorConstructorMap<any>, BaseMeta>
>()
})
})
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ export class Builder<
}

middleware<UOutContext extends Context, TInput, TOutput = any>( // = any here is important to make middleware can be used in any output by default
middleware: Middleware<TCurrentContext, UOutContext, TInput, TOutput, ORPCErrorConstructorMap<TErrorMap>, TMeta>,
): DecoratedMiddleware<TCurrentContext, UOutContext, TInput, TOutput, ORPCErrorConstructorMap<any>, TMeta> { // ORPCErrorConstructorMap<any> ensures middleware can used in any procedure
middleware: Middleware<TInitialContext, UOutContext, TInput, TOutput, ORPCErrorConstructorMap<TErrorMap>, TMeta>,
): DecoratedMiddleware<TInitialContext, UOutContext, TInput, TOutput, ORPCErrorConstructorMap<any>, TMeta> { // ORPCErrorConstructorMap<any> ensures middleware can used in any procedure
return decorateMiddleware(middleware)
}

Expand Down
8 changes: 4 additions & 4 deletions packages/server/src/implementer.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('Implementer', () => {
it('works', () => {
const mid = implementer.nested.middleware(({ context, next, path, procedure, errors, signal }, input, output) => {
expectTypeOf(input).toEqualTypeOf<unknown>()
expectTypeOf(context).toEqualTypeOf<CurrentContext>()
expectTypeOf(context).toEqualTypeOf<InitialContext>()
expectTypeOf(path).toEqualTypeOf<readonly string[]>()
expectTypeOf(procedure).toEqualTypeOf<
Procedure<Context, Context, AnySchema, AnySchema, ErrorMap, BaseMeta | Meta>
Expand All @@ -57,9 +57,9 @@ describe('Implementer', () => {
})
})

expectTypeOf(mid).toMatchTypeOf<
expectTypeOf(mid).toEqualTypeOf<
DecoratedMiddleware<
CurrentContext,
InitialContext,
{ extra: boolean },
unknown,
any,
Expand All @@ -77,7 +77,7 @@ describe('Implementer', () => {
implementer.middleware(({ next }, input: 'input', output: MiddlewareOutputFn<'output'>) => next()),
).toEqualTypeOf<
DecoratedMiddleware<
CurrentContext,
InitialContext,
Record<never, never>,
'input',
'output',
Expand Down
16 changes: 6 additions & 10 deletions packages/server/src/implementer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ export interface RouterImplementer<
> {
middleware<UOutContext extends Context, TInput, TOutput = any>( // = any here is important to make middleware can be used in any output by default
middleware: Middleware<
TCurrentContext,
TInitialContext,
UOutContext,
TInput,
TOutput,
ORPCErrorConstructorMap<InferContractRouterErrorMap<T>>,
InferContractRouterMeta<T>
>,
): DecoratedMiddleware<TCurrentContext, UOutContext, TInput, TOutput, ORPCErrorConstructorMap<any>, InferContractRouterMeta<T>> // ORPCErrorConstructorMap<any> ensures middleware can used in any procedure
): DecoratedMiddleware<TInitialContext, UOutContext, TInput, TOutput, ORPCErrorConstructorMap<any>, InferContractRouterMeta<T>> // ORPCErrorConstructorMap<any> ensures middleware can used in any procedure

use<UOutContext extends Context, UInContext extends Context = TCurrentContext>(
middleware: Middleware<
Expand Down Expand Up @@ -169,19 +169,15 @@ export type Implementer<
TCurrentContext extends Context ,
> =
& {
$context<U extends Context>(): Implementer<TContract, U, U>
$context<U extends Context>(): Implementer<TContract, U & Record<never, never>, U> // We need `& Record<never, never>` to deal with `has no properties in common with type` error
$config(config: BuilderConfig): Implementer<TContract, TInitialContext, TCurrentContext>
}
& ImplementerInternal<TContract, TInitialContext, TCurrentContext>

export function implement<
TContract extends AnyContractRouter,
TInitialContext extends Context,
TCurrentContext extends Context,
>(
contract: TContract,
export function implement<T extends AnyContractRouter, TContext extends Context = Record<never, never>>(
contract: T,
config: BuilderConfig = {},
): Implementer<TContract, TInitialContext, TCurrentContext> {
): Implementer<T, TContext, TContext> {
const implInternal = implementerInternal(contract, config, [])

const impl = new Proxy(implInternal, {
Expand Down