From 7e51813ae7c8f63ffd95fa18f9d445c265cf39e8 Mon Sep 17 00:00:00 2001 From: unnoq Date: Fri, 21 Mar 2025 09:51:59 +0700 Subject: [PATCH 1/5] wip --- .../server/src/builder-variants.test-d.ts | 32 ++-- packages/server/src/builder-variants.ts | 151 +++++++++--------- packages/server/src/builder.test-d.ts | 63 +------- packages/server/src/builder.test.ts | 1 + packages/server/src/builder.ts | 46 ++---- .../src/implementer-procedure.test-d.ts | 16 +- packages/server/src/implementer-procedure.ts | 50 +++--- .../server/src/implementer-variants.test-d.ts | 4 +- packages/server/src/implementer-variants.ts | 16 +- packages/server/src/implementer.test-d.ts | 4 +- packages/server/src/implementer.ts | 17 +- .../server/src/middleware-decorated.test-d.ts | 8 +- packages/server/src/middleware-decorated.ts | 44 ++--- .../server/src/procedure-decorated.test-d.ts | 8 +- packages/server/src/procedure-decorated.ts | 12 +- packages/shared/src/types.ts | 2 + 16 files changed, 193 insertions(+), 281 deletions(-) diff --git a/packages/server/src/builder-variants.test-d.ts b/packages/server/src/builder-variants.test-d.ts index 45bd355d3..42fd434b2 100644 --- a/packages/server/src/builder-variants.test-d.ts +++ b/packages/server/src/builder-variants.test-d.ts @@ -99,8 +99,8 @@ describe('BuilderWithMiddlewares', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match @@ -358,8 +358,8 @@ describe('ProcedureBuilder', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match @@ -552,8 +552,8 @@ describe('ProcedureBuilderWithInput', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match @@ -600,8 +600,8 @@ describe('ProcedureBuilderWithInput', () => { input => ({ invalid: true }), ) - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => { })).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => {}) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({}), input => ({ mapped: true })) // @ts-expect-error --- output is not match @@ -789,8 +789,8 @@ describe('ProcedureBuilderWithOutput', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match @@ -970,8 +970,8 @@ describe('ProcedureBuilderWithInputOutput', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match @@ -1018,8 +1018,8 @@ describe('ProcedureBuilderWithInputOutput', () => { input => ({ invalid: true }), ) - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => { })).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => {}) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({}), input => ({ mapped: true })) // @ts-expect-error --- output is not match @@ -1163,8 +1163,8 @@ describe('RouterBuilder', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match diff --git a/packages/server/src/builder-variants.ts b/packages/server/src/builder-variants.ts index 2ff4f45a2..30043e40e 100644 --- a/packages/server/src/builder-variants.ts +++ b/packages/server/src/builder-variants.ts @@ -1,6 +1,7 @@ import type { AnySchema, ContractRouter, ErrorMap, HTTPPath, InferSchemaInput, InferSchemaOutput, MergedErrorMap, Meta, Route, Schema } from '@orpc/contract' +import type { IntersectPick } from '@orpc/shared' import type { BuilderDef } from './builder' -import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' +import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { Lazy } from './lazy' import type { MapInputMiddleware, Middleware } from './middleware' @@ -30,7 +31,7 @@ export interface BuilderWithMiddlewares< TMeta > - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -39,15 +40,14 @@ export interface BuilderWithMiddlewares< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & BuilderWithMiddlewares< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): BuilderWithMiddlewares< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > 'meta'( meta: TMeta, @@ -103,7 +103,7 @@ export interface ProcedureBuilder< TMeta > - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -112,15 +112,14 @@ export interface ProcedureBuilder< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & ProcedureBuilder< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ProcedureBuilder< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > 'meta'( meta: TMeta, @@ -157,7 +156,7 @@ export interface ProcedureBuilderWithInput< errors: U, ): ProcedureBuilderWithInput, TMeta> - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -166,17 +165,16 @@ export interface ProcedureBuilderWithInput< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & ProcedureBuilderWithInput< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ProcedureBuilderWithInput< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -186,15 +184,14 @@ export interface ProcedureBuilderWithInput< TMeta >, mapInput: MapInputMiddleware, UInput>, - ): ContextExtendsGuard - & ProcedureBuilderWithInput< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ProcedureBuilderWithInput< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > 'meta'( meta: TMeta, @@ -234,7 +231,7 @@ export interface ProcedureBuilderWithOutput< TMeta > - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -243,15 +240,14 @@ export interface ProcedureBuilderWithOutput< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & ProcedureBuilderWithOutput< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ProcedureBuilderWithOutput< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > 'meta'( meta: TMeta, @@ -284,7 +280,7 @@ export interface ProcedureBuilderWithInputOutput< errors: U, ): ProcedureBuilderWithInputOutput, TMeta> - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -293,17 +289,16 @@ export interface ProcedureBuilderWithInputOutput< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & ProcedureBuilderWithInputOutput< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ProcedureBuilderWithInputOutput< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -313,15 +308,14 @@ export interface ProcedureBuilderWithInputOutput< TMeta >, mapInput: MapInputMiddleware, UInput>, - ): ContextExtendsGuard - & ProcedureBuilderWithInputOutput< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ProcedureBuilderWithInputOutput< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > 'meta'( meta: TMeta, @@ -348,7 +342,7 @@ export interface RouterBuilder< errors: U, ): RouterBuilder, TMeta> - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -357,13 +351,12 @@ export interface RouterBuilder< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & RouterBuilder< - MergedInitialContext, - MergedCurrentContext, - TErrorMap, - TMeta - > + ): RouterBuilder< + MergedInitialContext, + MergedCurrentContext, + TErrorMap, + TMeta + > 'prefix'(prefix: HTTPPath): RouterBuilder diff --git a/packages/server/src/builder.test-d.ts b/packages/server/src/builder.test-d.ts index 6392719cc..a90624c2e 100644 --- a/packages/server/src/builder.test-d.ts +++ b/packages/server/src/builder.test-d.ts @@ -241,62 +241,14 @@ describe('Builder', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- Invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match builder.use(({ next }, input, output: MiddlewareOutputFn<'invalid'>) => next({})) }) - it('with map input', () => { - const applied = builder.use(({ context, next, path, procedure, errors, signal }, input: { mapped: boolean }, output) => { - expectTypeOf(input).toEqualTypeOf<{ mapped: boolean }>() - expectTypeOf(context).toEqualTypeOf() - expectTypeOf(path).toEqualTypeOf() - expectTypeOf(procedure).toEqualTypeOf< - Procedure - >() - expectTypeOf(output).toEqualTypeOf>() - expectTypeOf(errors).toEqualTypeOf>() - expectTypeOf(signal).toEqualTypeOf>() - - return next({ - context: { - extra: true, - }, - }) - }, (input) => { - expectTypeOf(input).toEqualTypeOf() - - return { mapped: true } - }) - - expectTypeOf(applied).toEqualTypeOf< - BuilderWithMiddlewares< - InitialContext & Record, - Omit & { extra: boolean }, - typeof inputSchema, - typeof outputSchema, - typeof baseErrorMap, - BaseMeta - > - >() - - builder.use( - ({ context, next, path, procedure, errors, signal }, input: { mapped: boolean }, output) => next(), - // @ts-expect-error --- invalid map input - input => ({ invalid: true }), - ) - - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => { })).toEqualTypeOf() - // @ts-expect-error --- input is not match - builder.use(({ next }, input: 'invalid') => next({}), input => ({ mapped: true })) - // @ts-expect-error --- output is not match - builder.use(({ next }, input, output: MiddlewareOutputFn<'invalid'>) => next({}), input => ({ mapped: true })) - }) - it('with TInContext', () => { const mid = {} as Middleware<{ cacheable?: boolean } & Record, Record, unknown, unknown, ORPCErrorConstructorMap, BaseMeta> @@ -310,17 +262,6 @@ describe('Builder', () => { BaseMeta > >() - - expectTypeOf(builder.use(mid, () => { })).toEqualTypeOf< - BuilderWithMiddlewares< - InitialContext & { cacheable?: boolean }, - Omit & Record, - typeof inputSchema, - typeof outputSchema, - typeof baseErrorMap, - BaseMeta - > - >() }) }) diff --git a/packages/server/src/builder.test.ts b/packages/server/src/builder.test.ts index d3b760bec..9f603c336 100644 --- a/packages/server/src/builder.test.ts +++ b/packages/server/src/builder.test.ts @@ -167,6 +167,7 @@ describe('builder', () => { mapInput: (map: any) => [mid, map] as any, }) as any) + // @ts-expect-error --- this builder support .use with map input but not type const applied = builder.use(mid2, map2) expect(applied).instanceOf(Builder) diff --git a/packages/server/src/builder.ts b/packages/server/src/builder.ts index 10d91e8f6..487c040d4 100644 --- a/packages/server/src/builder.ts +++ b/packages/server/src/builder.ts @@ -1,6 +1,7 @@ import type { AnySchema, ContractProcedureDef, ContractRouter, ErrorMap, HTTPPath, MergedErrorMap, Meta, Route, Schema } from '@orpc/contract' +import type { IntersectPick } from '@orpc/shared' import type { BuilderWithMiddlewares, ProcedureBuilder, ProcedureBuilderWithInput, ProcedureBuilderWithOutput, RouterBuilder } from './builder-variants' -import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' +import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { Lazy } from './lazy' import type { AnyMiddleware, MapInputMiddleware, Middleware } from './middleware' @@ -132,7 +133,7 @@ export class Builder< }) } - use( + use = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -141,35 +142,14 @@ export class Builder< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & BuilderWithMiddlewares< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > - - use( - middleware: Middleware< - UInContext, - UOutContext, - UInput, - unknown, - ORPCErrorConstructorMap, - TMeta - >, - mapInput: MapInputMiddleware, - ): ContextExtendsGuard - & BuilderWithMiddlewares< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): BuilderWithMiddlewares< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > use( middleware: AnyMiddleware, @@ -191,7 +171,7 @@ export class Builder< return new Builder({ ...this['~orpc'], meta: mergeMeta(this['~orpc'].meta, meta), - }) + }) as any } route( @@ -200,7 +180,7 @@ export class Builder< return new Builder({ ...this['~orpc'], route: mergeRoute(this['~orpc'].route, route), - }) + }) as any } input( diff --git a/packages/server/src/implementer-procedure.test-d.ts b/packages/server/src/implementer-procedure.test-d.ts index ea86ed7d3..9cedca7dd 100644 --- a/packages/server/src/implementer-procedure.test-d.ts +++ b/packages/server/src/implementer-procedure.test-d.ts @@ -90,8 +90,8 @@ describe('ImplementedProcedure', () => { > >() - // invalid TInContext - expectTypeOf(implemented.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + implemented.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match implemented.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match @@ -129,8 +129,8 @@ describe('ImplementedProcedure', () => { > >() - // invalid TInContext - expectTypeOf(implemented.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => {})).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + implemented.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => { }) // @ts-expect-error --- input is not match implemented.use(({ next }, input: 'invalid') => next({}), () => {}) // @ts-expect-error --- output is not match @@ -265,8 +265,8 @@ describe('ProcedureImplementer', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match @@ -313,8 +313,8 @@ describe('ProcedureImplementer', () => { input => ({ invalid: true }), ) - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => {})).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => { }) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({}), input => ({ mapped: true })) // @ts-expect-error --- output is not match diff --git a/packages/server/src/implementer-procedure.ts b/packages/server/src/implementer-procedure.ts index 7344d1d53..196718059 100644 --- a/packages/server/src/implementer-procedure.ts +++ b/packages/server/src/implementer-procedure.ts @@ -1,6 +1,6 @@ import type { ClientContext, ClientRest } from '@orpc/client' import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, Meta } from '@orpc/contract' -import type { MaybeOptionalOptions } from '@orpc/shared' +import type { IntersectPick, MaybeOptionalOptions } from '@orpc/shared' import type { BuilderDef } from './builder' import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' @@ -19,7 +19,7 @@ export interface ImplementedProcedure< TErrorMap extends ErrorMap, TMeta extends Meta, > extends Procedure { - use( + use = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -28,8 +28,7 @@ export interface ImplementedProcedure< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & ContextExtendsGuard, TCurrentContext> + ): ContextExtendsGuard, TCurrentContext> & ImplementedProcedure< MergedInitialContext, MergedCurrentContext, @@ -39,7 +38,7 @@ export interface ImplementedProcedure< TMeta > - use( + use = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -49,8 +48,7 @@ export interface ImplementedProcedure< TMeta >, mapInput: MapInputMiddleware, UInput>, - ): ContextExtendsGuard - & ContextExtendsGuard, TCurrentContext> + ): ContextExtendsGuard, TCurrentContext> & ImplementedProcedure< MergedInitialContext, MergedCurrentContext, @@ -108,7 +106,7 @@ export interface ProcedureImplementer< > { '~orpc': BuilderDef - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -117,17 +115,16 @@ export interface ProcedureImplementer< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & ProcedureImplementer< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ProcedureImplementer< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > - 'use'( + 'use' = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -137,15 +134,14 @@ export interface ProcedureImplementer< TMeta >, mapInput: MapInputMiddleware, UInput>, - ): ContextExtendsGuard - & ProcedureImplementer< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ProcedureImplementer< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > 'handler'( handler: ProcedureHandler, InferSchemaInput, TErrorMap, TMeta>, diff --git a/packages/server/src/implementer-variants.test-d.ts b/packages/server/src/implementer-variants.test-d.ts index 27c756180..e5c9e513f 100644 --- a/packages/server/src/implementer-variants.test-d.ts +++ b/packages/server/src/implementer-variants.test-d.ts @@ -47,8 +47,8 @@ describe('ImplementerWithMiddlewares', () => { > >() - // invalid TInContext - expectTypeOf(implementer.nested.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + implementer.nested.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match implementer.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match diff --git a/packages/server/src/implementer-variants.ts b/packages/server/src/implementer-variants.ts index 201ed26bb..8147c7bc3 100644 --- a/packages/server/src/implementer-variants.ts +++ b/packages/server/src/implementer-variants.ts @@ -1,5 +1,6 @@ import type { AnyContractRouter, ContractProcedure, InferContractRouterErrorMap, InferContractRouterMeta } from '@orpc/contract' -import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' +import type { IntersectPick } from '@orpc/shared' +import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { ProcedureImplementer } from './implementer-procedure' import type { Lazy } from './lazy' @@ -12,7 +13,7 @@ export interface RouterImplementerWithMiddlewares< TInitialContext extends Context, TCurrentContext extends Context, > { - use( + use = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -21,12 +22,11 @@ export interface RouterImplementerWithMiddlewares< ORPCErrorConstructorMap>, InferContractRouterMeta >, - ): ContextExtendsGuard - & ImplementerInternalWithMiddlewares< - T, - MergedInitialContext, - MergedCurrentContext - > + ): ImplementerInternalWithMiddlewares< + T, + MergedInitialContext, + MergedCurrentContext + > router>( router: U): EnhancedRouter> diff --git a/packages/server/src/implementer.test-d.ts b/packages/server/src/implementer.test-d.ts index 7485a341b..fa502c7f6 100644 --- a/packages/server/src/implementer.test-d.ts +++ b/packages/server/src/implementer.test-d.ts @@ -116,8 +116,8 @@ describe('Implementer', () => { > >() - // invalid TInContext - expectTypeOf(implementer.nested.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + implementer.nested.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match implementer.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match diff --git a/packages/server/src/implementer.ts b/packages/server/src/implementer.ts index c0c47e6da..26d62063e 100644 --- a/packages/server/src/implementer.ts +++ b/packages/server/src/implementer.ts @@ -1,6 +1,6 @@ import type { AnyContractRouter, ContractProcedure, InferContractRouterErrorMap, InferContractRouterMeta } from '@orpc/contract' -import type { AnyFunction } from '@orpc/shared' -import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' +import type { AnyFunction, IntersectPick } from '@orpc/shared' +import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { ProcedureImplementer } from './implementer-procedure' import type { ImplementerInternalWithMiddlewares } from './implementer-variants' @@ -32,7 +32,7 @@ export interface RouterImplementer< >, ): DecoratedMiddleware, InferContractRouterMeta> // ORPCErrorConstructorMap ensures middleware can used in any procedure - use( + use = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -41,12 +41,11 @@ export interface RouterImplementer< ORPCErrorConstructorMap>, InferContractRouterMeta >, - ): ContextExtendsGuard - & ImplementerInternalWithMiddlewares< - T, - MergedInitialContext, - MergedCurrentContext - > + ): ImplementerInternalWithMiddlewares< + T, + MergedInitialContext, + MergedCurrentContext + > router>( router: U): EnhancedRouter> diff --git a/packages/server/src/middleware-decorated.test-d.ts b/packages/server/src/middleware-decorated.test-d.ts index 34d83a178..0a62a4d20 100644 --- a/packages/server/src/middleware-decorated.test-d.ts +++ b/packages/server/src/middleware-decorated.test-d.ts @@ -79,8 +79,8 @@ describe('DecoratedMiddleware', () => { > >() - // invalid TInContext - expectTypeOf(decorated.concat({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + decorated.concat({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- output is not match decorated.concat(({ next }, input, output: MiddlewareOutputFn<'invalid'>) => next({})) }) @@ -125,8 +125,8 @@ describe('DecoratedMiddleware', () => { input => ({ invalid: true }), ) - // invalid TInContext - expectTypeOf(decorated.concat({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => { })).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + decorated.concat({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => { }) // @ts-expect-error --- output is not match decorated.concat(({ next }, input, output: MiddlewareOutputFn<'invalid'>) => next({}), input => ({ mapped: true })) }) diff --git a/packages/server/src/middleware-decorated.ts b/packages/server/src/middleware-decorated.ts index 3e8c612dc..1eaf0ad4a 100644 --- a/packages/server/src/middleware-decorated.ts +++ b/packages/server/src/middleware-decorated.ts @@ -1,5 +1,6 @@ import type { Meta } from '@orpc/contract' -import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' +import type { IntersectPick } from '@orpc/shared' +import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { AnyMiddleware, MapInputMiddleware, Middleware } from './middleware' @@ -15,7 +16,10 @@ export interface DecoratedMiddleware< map: MapInputMiddleware, ): DecoratedMiddleware - concat>( + concat< + UOutContext extends Context, + UInContext extends IntersectPick, UInContext> = MergedCurrentContext, + >( middleware: Middleware< UInContext, UOutContext, @@ -24,20 +28,19 @@ export interface DecoratedMiddleware< TErrorConstructorMap, TMeta >, - ): ContextExtendsGuard, UInContext> - & DecoratedMiddleware< - MergedInitialContext>, - MergedCurrentContext, - TInput, - TOutput, - TErrorConstructorMap, - TMeta - > + ): DecoratedMiddleware< + MergedInitialContext>, + MergedCurrentContext, + TInput, + TOutput, + TErrorConstructorMap, + TMeta + > concat< UOutContext extends Context, UMappedInput, - UInContext extends Context = MergedCurrentContext, + UInContext extends IntersectPick, UInContext> = MergedCurrentContext, >( middleware: Middleware< UInContext, @@ -48,15 +51,14 @@ export interface DecoratedMiddleware< TMeta >, mapInput: MapInputMiddleware, - ): ContextExtendsGuard, UInContext> - & DecoratedMiddleware< - MergedInitialContext>, - MergedCurrentContext, - TInput, - TOutput, - TErrorConstructorMap, - TMeta - > + ): DecoratedMiddleware< + MergedInitialContext>, + MergedCurrentContext, + TInput, + TOutput, + TErrorConstructorMap, + TMeta + > } export function decorateMiddleware< diff --git a/packages/server/src/procedure-decorated.test-d.ts b/packages/server/src/procedure-decorated.test-d.ts index d2de10b61..412be9c3c 100644 --- a/packages/server/src/procedure-decorated.test-d.ts +++ b/packages/server/src/procedure-decorated.test-d.ts @@ -118,8 +118,8 @@ describe('DecoratedProcedure', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>)).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match @@ -157,8 +157,8 @@ describe('DecoratedProcedure', () => { > >() - // invalid TInContext - expectTypeOf(builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => { })).toEqualTypeOf() + // @ts-expect-error --- invalid TInContext + builder.use({} as Middleware<{ auth: 'invalid' }, any, any, any, any, any>, () => {}) // @ts-expect-error --- input is not match builder.use(({ next }, input: 'invalid') => next({}), () => {}) // @ts-expect-error --- output is not match diff --git a/packages/server/src/procedure-decorated.ts b/packages/server/src/procedure-decorated.ts index 43f96e24d..bf040b6d5 100644 --- a/packages/server/src/procedure-decorated.ts +++ b/packages/server/src/procedure-decorated.ts @@ -1,6 +1,6 @@ import type { ClientContext, ClientRest } from '@orpc/client' import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, MergedErrorMap, Meta, Route } from '@orpc/contract' -import type { MaybeOptionalOptions } from '@orpc/shared' +import type { IntersectPick, MaybeOptionalOptions } from '@orpc/shared' import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { AnyMiddleware, MapInputMiddleware, Middleware } from './middleware' @@ -53,7 +53,7 @@ export class DecoratedProcedure< }) } - use( + use = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -62,8 +62,7 @@ export class DecoratedProcedure< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard - & ContextExtendsGuard, TCurrentContext> + ): ContextExtendsGuard, TCurrentContext> & DecoratedProcedure< MergedInitialContext, MergedCurrentContext, @@ -73,7 +72,7 @@ export class DecoratedProcedure< TMeta > - use( + use = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -83,8 +82,7 @@ export class DecoratedProcedure< TMeta >, mapInput: MapInputMiddleware, UInput>, - ): ContextExtendsGuard - & ContextExtendsGuard, TCurrentContext> + ): ContextExtendsGuard, TCurrentContext> & DecoratedProcedure< MergedInitialContext, MergedCurrentContext, diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts index c7e113ae6..73deb37ce 100644 --- a/packages/shared/src/types.ts +++ b/packages/shared/src/types.ts @@ -3,3 +3,5 @@ export type MaybeOptionalOptions = Record extends TOptio : [options: TOptions] export type SetOptional = Omit & Partial> + +export type IntersectPick = Pick From be90883f5e1f45758938c061d9fa982563744a1a Mon Sep 17 00:00:00 2001 From: unnoq Date: Fri, 21 Mar 2025 10:01:06 +0700 Subject: [PATCH 2/5] wip --- packages/server/src/context.test-d.ts | 29 +------------- packages/server/src/context.ts | 2 - .../src/implementer-procedure.test-d.ts | 8 ++-- packages/server/src/implementer-procedure.ts | 40 +++++++++---------- .../server/src/procedure-decorated.test-d.ts | 8 ++-- packages/server/src/procedure-decorated.ts | 40 +++++++++---------- 6 files changed, 47 insertions(+), 80 deletions(-) diff --git a/packages/server/src/context.test-d.ts b/packages/server/src/context.test-d.ts index d323bf837..c7a83e7e1 100644 --- a/packages/server/src/context.test-d.ts +++ b/packages/server/src/context.test-d.ts @@ -1,4 +1,4 @@ -import type { ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' +import type { MergedCurrentContext, MergedInitialContext } from './context' it('MergedInitialContext', () => { expectTypeOf>().toMatchTypeOf<{ a: string, b: number }>() @@ -10,30 +10,3 @@ it('MergedCurrentContext', () => { expectTypeOf>().toMatchTypeOf<{ a: string, b: number }>() expectTypeOf>().toMatchTypeOf<{ a: number }>() }) - -interface Empty { - -} - -it('ContextExtendsGuard', () => { - expectTypeOf < ContextExtendsGuard< { a: string, b: string }, { a: string }>>().toEqualTypeOf() - expectTypeOf>().toEqualTypeOf() - expectTypeOf < ContextExtendsGuard< { a: string, b: string }, Empty>>().toEqualTypeOf() - expectTypeOf < ContextExtendsGuard< { a: string, b: string }, Record>>().toEqualTypeOf() - expectTypeOf>().toEqualTypeOf() - - expectTypeOf < ContextExtendsGuard < { a: string }, { a: string, b: string }>>().toEqualTypeOf() - expectTypeOf < ContextExtendsGuard < { a: number }, { a: string }>>().toEqualTypeOf() - expectTypeOf>().toEqualTypeOf() - - expectTypeOf>().toEqualTypeOf() - expectTypeOf>().toEqualTypeOf() - expectTypeOf>().toEqualTypeOf() - - /** - * We can use `& Record` to deal with `has no properties in common with type` error - */ - expectTypeOf>>().toEqualTypeOf() - expectTypeOf>>().toEqualTypeOf() - expectTypeOf>>().toEqualTypeOf() -}) diff --git a/packages/server/src/context.ts b/packages/server/src/context.ts index 3826c73f9..45fb73326 100644 --- a/packages/server/src/context.ts +++ b/packages/server/src/context.ts @@ -14,5 +14,3 @@ export function mergeCurrentContext( ): MergedCurrentContext { return { ...context, ...other } } - -export type ContextExtendsGuard = T extends U ? unknown : never diff --git a/packages/server/src/implementer-procedure.test-d.ts b/packages/server/src/implementer-procedure.test-d.ts index 9cedca7dd..e4c9dcd9d 100644 --- a/packages/server/src/implementer-procedure.test-d.ts +++ b/packages/server/src/implementer-procedure.test-d.ts @@ -96,8 +96,8 @@ describe('ImplementedProcedure', () => { implemented.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match implemented.use(({ next }, input, output: MiddlewareOutputFn<'invalid'>) => next({})) - // conflict context - expectTypeOf(implemented.use(({ next }) => next({ context: { db: undefined } }))).toEqualTypeOf() + // @ts-expect-error --- conflict context + implemented.use(({ next }) => next({ context: { db: undefined } })) }) it('with map input', () => { @@ -135,8 +135,8 @@ describe('ImplementedProcedure', () => { implemented.use(({ next }, input: 'invalid') => next({}), () => {}) // @ts-expect-error --- output is not match implemented.use(({ next }, input, output: MiddlewareOutputFn<'invalid'>) => next({}), () => {}) - // conflict context but not detected - expectTypeOf(implemented.use(({ next }) => next({ context: { db: undefined } }), () => {})).toEqualTypeOf() + // @ts-expect-error --- conflict context + implemented.use(({ next }) => next({ context: { db: undefined } }), () => { }) }) it('with TInContext', () => { diff --git a/packages/server/src/implementer-procedure.ts b/packages/server/src/implementer-procedure.ts index 196718059..0ac659582 100644 --- a/packages/server/src/implementer-procedure.ts +++ b/packages/server/src/implementer-procedure.ts @@ -2,7 +2,7 @@ import type { ClientContext, ClientRest } from '@orpc/client' import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, Meta } from '@orpc/contract' import type { IntersectPick, MaybeOptionalOptions } from '@orpc/shared' import type { BuilderDef } from './builder' -import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' +import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { MapInputMiddleware, Middleware } from './middleware' import type { Procedure, ProcedureHandler } from './procedure' @@ -19,7 +19,7 @@ export interface ImplementedProcedure< TErrorMap extends ErrorMap, TMeta extends Meta, > extends Procedure { - use = TCurrentContext>( + use, UInContext extends IntersectPick = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -28,17 +28,16 @@ export interface ImplementedProcedure< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard, TCurrentContext> - & ImplementedProcedure< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ImplementedProcedure< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > - use = TCurrentContext>( + use, UInput, UInContext extends IntersectPick = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -48,15 +47,14 @@ export interface ImplementedProcedure< TMeta >, mapInput: MapInputMiddleware, UInput>, - ): ContextExtendsGuard, TCurrentContext> - & ImplementedProcedure< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): ImplementedProcedure< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > /** * Make this procedure callable (works like a function while still being a procedure). diff --git a/packages/server/src/procedure-decorated.test-d.ts b/packages/server/src/procedure-decorated.test-d.ts index 412be9c3c..6ecbc06b2 100644 --- a/packages/server/src/procedure-decorated.test-d.ts +++ b/packages/server/src/procedure-decorated.test-d.ts @@ -124,8 +124,8 @@ describe('DecoratedProcedure', () => { builder.use(({ next }, input: 'invalid') => next({})) // @ts-expect-error --- output is not match builder.use(({ next }, input, output: MiddlewareOutputFn<'invalid'>) => next({})) - // conflict context but not detected - expectTypeOf(builder.use(({ next }) => next({ context: { db: undefined } }))).toEqualTypeOf() + // @ts-expect-error --- conflict context + builder.use(({ next }) => next({ context: { db: undefined } })) }) it('with map input', () => { @@ -163,8 +163,8 @@ describe('DecoratedProcedure', () => { builder.use(({ next }, input: 'invalid') => next({}), () => {}) // @ts-expect-error --- output is not match builder.use(({ next }, input, output: MiddlewareOutputFn<'invalid'>) => next({}), () => {}) - // conflict context but not detected - expectTypeOf(builder.use(({ next }) => next({ context: { db: undefined } }), () => {})).toEqualTypeOf() + // @ts-expect-error --- conflict context + builder.use(({ next }) => next({ context: { db: undefined } }), () => { }) }) it('with TInContext', () => { diff --git a/packages/server/src/procedure-decorated.ts b/packages/server/src/procedure-decorated.ts index bf040b6d5..b3f758ed0 100644 --- a/packages/server/src/procedure-decorated.ts +++ b/packages/server/src/procedure-decorated.ts @@ -1,7 +1,7 @@ import type { ClientContext, ClientRest } from '@orpc/client' import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, MergedErrorMap, Meta, Route } from '@orpc/contract' import type { IntersectPick, MaybeOptionalOptions } from '@orpc/shared' -import type { Context, ContextExtendsGuard, MergedCurrentContext, MergedInitialContext } from './context' +import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { AnyMiddleware, MapInputMiddleware, Middleware } from './middleware' import type { CreateProcedureClientOptions, ProcedureClient } from './procedure-client' @@ -53,7 +53,7 @@ export class DecoratedProcedure< }) } - use = TCurrentContext>( + use, UInContext extends IntersectPick = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -62,17 +62,16 @@ export class DecoratedProcedure< ORPCErrorConstructorMap, TMeta >, - ): ContextExtendsGuard, TCurrentContext> - & DecoratedProcedure< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): DecoratedProcedure< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > - use = TCurrentContext>( + use, UInput, UInContext extends IntersectPick = TCurrentContext>( middleware: Middleware< UInContext, UOutContext, @@ -82,15 +81,14 @@ export class DecoratedProcedure< TMeta >, mapInput: MapInputMiddleware, UInput>, - ): ContextExtendsGuard, TCurrentContext> - & DecoratedProcedure< - MergedInitialContext, - MergedCurrentContext, - TInputSchema, - TOutputSchema, - TErrorMap, - TMeta - > + ): DecoratedProcedure< + MergedInitialContext, + MergedCurrentContext, + TInputSchema, + TOutputSchema, + TErrorMap, + TMeta + > use(middleware: AnyMiddleware, mapInput?: MapInputMiddleware): DecoratedProcedure { const mapped = mapInput From a18ba0e5737c7989372e98b9e03b174aa05db760 Mon Sep 17 00:00:00 2001 From: unnoq Date: Fri, 21 Mar 2025 10:42:24 +0700 Subject: [PATCH 3/5] wip --- packages/server/src/builder-variants.ts | 33 ++++++++++---------- packages/server/src/builder.test-d.ts | 7 ++--- packages/server/src/builder.ts | 7 ++--- packages/server/src/implementer-procedure.ts | 16 +++++----- packages/server/src/implementer-variants.ts | 5 ++- packages/server/src/implementer.test-d.ts | 7 ++--- packages/server/src/implementer.ts | 8 ++--- packages/server/src/middleware-decorated.ts | 9 +++--- packages/server/src/procedure-decorated.ts | 8 ++--- 9 files changed, 45 insertions(+), 55 deletions(-) diff --git a/packages/server/src/builder-variants.ts b/packages/server/src/builder-variants.ts index 30043e40e..5ea42b0f6 100644 --- a/packages/server/src/builder-variants.ts +++ b/packages/server/src/builder-variants.ts @@ -1,5 +1,4 @@ import type { AnySchema, ContractRouter, ErrorMap, HTTPPath, InferSchemaInput, InferSchemaOutput, MergedErrorMap, Meta, Route, Schema } from '@orpc/contract' -import type { IntersectPick } from '@orpc/shared' import type { BuilderDef } from './builder' import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' @@ -31,9 +30,9 @@ export interface BuilderWithMiddlewares< TMeta > - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, unknown, unknown, @@ -103,9 +102,9 @@ export interface ProcedureBuilder< TMeta > - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, unknown, unknown, @@ -156,9 +155,9 @@ export interface ProcedureBuilderWithInput< errors: U, ): ProcedureBuilderWithInput, TMeta> - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, InferSchemaOutput, unknown, @@ -174,9 +173,9 @@ export interface ProcedureBuilderWithInput< TMeta > - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, UInput, unknown, @@ -231,9 +230,9 @@ export interface ProcedureBuilderWithOutput< TMeta > - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, unknown, InferSchemaInput, @@ -280,9 +279,9 @@ export interface ProcedureBuilderWithInputOutput< errors: U, ): ProcedureBuilderWithInputOutput, TMeta> - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, InferSchemaOutput, InferSchemaInput, @@ -298,9 +297,9 @@ export interface ProcedureBuilderWithInputOutput< TMeta > - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, UInput, InferSchemaInput, @@ -342,9 +341,9 @@ export interface RouterBuilder< errors: U, ): RouterBuilder, TMeta> - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, unknown, unknown, diff --git a/packages/server/src/builder.test-d.ts b/packages/server/src/builder.test-d.ts index a90624c2e..5e33d79f1 100644 --- a/packages/server/src/builder.test-d.ts +++ b/packages/server/src/builder.test-d.ts @@ -173,18 +173,15 @@ describe('Builder', () => { }) }), ).toEqualTypeOf< - DecoratedMiddleware, BaseMeta> + DecoratedMiddleware >() - - // @ts-expect-error --- conflict context - builder.middleware(({ next }) => next({ db: 123 })) }) it('can type input and output', () => { expectTypeOf( builder.middleware(({ next }, input: 'input', output: MiddlewareOutputFn<'output'>) => next()), ).toEqualTypeOf< - DecoratedMiddleware, 'input', 'output', ORPCErrorConstructorMap, BaseMeta> + DecoratedMiddleware, 'input', 'output', any, BaseMeta> >() }) }) diff --git a/packages/server/src/builder.ts b/packages/server/src/builder.ts index 487c040d4..69bb0aac1 100644 --- a/packages/server/src/builder.ts +++ b/packages/server/src/builder.ts @@ -1,5 +1,4 @@ import type { AnySchema, ContractProcedureDef, ContractRouter, ErrorMap, HTTPPath, MergedErrorMap, Meta, Route, Schema } from '@orpc/contract' -import type { IntersectPick } from '@orpc/shared' import type { BuilderWithMiddlewares, ProcedureBuilder, ProcedureBuilderWithInput, ProcedureBuilderWithOutput, RouterBuilder } from './builder-variants' import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' @@ -120,7 +119,7 @@ export class Builder< middleware( // = any here is important to make middleware can be used in any output by default middleware: Middleware, TMeta>, - ): DecoratedMiddleware, TMeta> { // ORPCErrorConstructorMap ensures middleware can used in any procedure + ): DecoratedMiddleware { // any ensures middleware can used in any procedure return decorateMiddleware(middleware) } @@ -133,9 +132,9 @@ export class Builder< }) } - use = TCurrentContext>( + use( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, unknown, unknown, diff --git a/packages/server/src/implementer-procedure.ts b/packages/server/src/implementer-procedure.ts index 0ac659582..47568ccc7 100644 --- a/packages/server/src/implementer-procedure.ts +++ b/packages/server/src/implementer-procedure.ts @@ -19,9 +19,9 @@ export interface ImplementedProcedure< TErrorMap extends ErrorMap, TMeta extends Meta, > extends Procedure { - use, UInContext extends IntersectPick = TCurrentContext>( + use, UInContext extends Context = TCurrentContext>( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, InferSchemaOutput, InferSchemaInput, @@ -37,9 +37,9 @@ export interface ImplementedProcedure< TMeta > - use, UInput, UInContext extends IntersectPick = TCurrentContext>( + use, UInput, UInContext extends Context = TCurrentContext>( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, UInput, InferSchemaInput, @@ -104,9 +104,9 @@ export interface ProcedureImplementer< > { '~orpc': BuilderDef - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, InferSchemaOutput, InferSchemaInput, @@ -122,9 +122,9 @@ export interface ProcedureImplementer< TMeta > - 'use' = TCurrentContext>( + 'use'( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, UInput, InferSchemaInput, diff --git a/packages/server/src/implementer-variants.ts b/packages/server/src/implementer-variants.ts index 8147c7bc3..e65bb65db 100644 --- a/packages/server/src/implementer-variants.ts +++ b/packages/server/src/implementer-variants.ts @@ -1,5 +1,4 @@ import type { AnyContractRouter, ContractProcedure, InferContractRouterErrorMap, InferContractRouterMeta } from '@orpc/contract' -import type { IntersectPick } from '@orpc/shared' import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { ProcedureImplementer } from './implementer-procedure' @@ -13,9 +12,9 @@ export interface RouterImplementerWithMiddlewares< TInitialContext extends Context, TCurrentContext extends Context, > { - use = TCurrentContext>( + use( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, unknown, unknown, diff --git a/packages/server/src/implementer.test-d.ts b/packages/server/src/implementer.test-d.ts index fa502c7f6..789ee5662 100644 --- a/packages/server/src/implementer.test-d.ts +++ b/packages/server/src/implementer.test-d.ts @@ -63,13 +63,10 @@ describe('Implementer', () => { { extra: boolean }, unknown, any, - ORPCErrorConstructorMap, + any, Meta | BaseMeta > >() - - // @ts-expect-error --- conflict context - implementer.middleware(({ next }) => next({ db: 123 })) }) it('can type input and output', () => { @@ -81,7 +78,7 @@ describe('Implementer', () => { Record, 'input', 'output', - ORPCErrorConstructorMap, + any, Meta | BaseMeta > >() diff --git a/packages/server/src/implementer.ts b/packages/server/src/implementer.ts index 26d62063e..c72e6755e 100644 --- a/packages/server/src/implementer.ts +++ b/packages/server/src/implementer.ts @@ -1,5 +1,5 @@ import type { AnyContractRouter, ContractProcedure, InferContractRouterErrorMap, InferContractRouterMeta } from '@orpc/contract' -import type { AnyFunction, IntersectPick } from '@orpc/shared' +import type { AnyFunction } from '@orpc/shared' import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { ProcedureImplementer } from './implementer-procedure' @@ -30,11 +30,11 @@ export interface RouterImplementer< ORPCErrorConstructorMap>, InferContractRouterMeta >, - ): DecoratedMiddleware, InferContractRouterMeta> // ORPCErrorConstructorMap ensures middleware can used in any procedure + ): DecoratedMiddleware> // any ensures middleware can used in any procedure - use = TCurrentContext>( + use( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, unknown, unknown, diff --git a/packages/server/src/middleware-decorated.ts b/packages/server/src/middleware-decorated.ts index 1eaf0ad4a..e716971e0 100644 --- a/packages/server/src/middleware-decorated.ts +++ b/packages/server/src/middleware-decorated.ts @@ -1,5 +1,4 @@ import type { Meta } from '@orpc/contract' -import type { IntersectPick } from '@orpc/shared' import type { Context, MergedCurrentContext, MergedInitialContext } from './context' import type { ORPCErrorConstructorMap } from './error' import type { AnyMiddleware, MapInputMiddleware, Middleware } from './middleware' @@ -18,10 +17,10 @@ export interface DecoratedMiddleware< concat< UOutContext extends Context, - UInContext extends IntersectPick, UInContext> = MergedCurrentContext, + UInContext extends Context = MergedCurrentContext, >( middleware: Middleware< - UInContext, + UInContext | MergedCurrentContext, UOutContext, TInput, TOutput, @@ -40,10 +39,10 @@ export interface DecoratedMiddleware< concat< UOutContext extends Context, UMappedInput, - UInContext extends IntersectPick, UInContext> = MergedCurrentContext, + UInContext extends Context = MergedCurrentContext, >( middleware: Middleware< - UInContext, + UInContext | MergedCurrentContext, UOutContext, UMappedInput, TOutput, diff --git a/packages/server/src/procedure-decorated.ts b/packages/server/src/procedure-decorated.ts index b3f758ed0..703e05857 100644 --- a/packages/server/src/procedure-decorated.ts +++ b/packages/server/src/procedure-decorated.ts @@ -53,9 +53,9 @@ export class DecoratedProcedure< }) } - use, UInContext extends IntersectPick = TCurrentContext>( + use, UInContext extends Context = TCurrentContext>( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, InferSchemaOutput, InferSchemaInput, @@ -71,9 +71,9 @@ export class DecoratedProcedure< TMeta > - use, UInput, UInContext extends IntersectPick = TCurrentContext>( + use, UInput, UInContext extends Context = TCurrentContext>( middleware: Middleware< - UInContext, + UInContext | TCurrentContext, UOutContext, UInput, InferSchemaInput, From 2cb68b0f9be14988c421dd881a25d4724c7e86af Mon Sep 17 00:00:00 2001 From: unnoq Date: Fri, 21 Mar 2025 13:20:24 +0700 Subject: [PATCH 4/5] tests --- packages/shared/src/types.test-d.ts | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 packages/shared/src/types.test-d.ts diff --git a/packages/shared/src/types.test-d.ts b/packages/shared/src/types.test-d.ts new file mode 100644 index 000000000..62d148bc3 --- /dev/null +++ b/packages/shared/src/types.test-d.ts @@ -0,0 +1,35 @@ +import type { IntersectPick, MaybeOptionalOptions, SetOptional } from './types' + +it('MaybeOptionalOptions', () => { + const a = (...[options]: MaybeOptionalOptions<{ a: number }>) => { + expectTypeOf(options).toEqualTypeOf<{ a: number }>() + } + + // @ts-expect-error - options is required + a() + // @ts-expect-error - options is invalid + a({ a: '1' }) + a({ a: 1 }) + + const b = (...[options]: MaybeOptionalOptions<{ b?: number }>) => { + expectTypeOf(options).toEqualTypeOf<{ b?: number } | undefined>() + } + + b() + // @ts-expect-error - options is invalid + a({ b: '1' }) + b({ b: 1 }) +}) + +it('SetOptional', () => { + expectTypeOf>().toMatchTypeOf<{ a?: number }>() + expectTypeOf>().toMatchTypeOf<{ a?: number }>() +}) + +interface Empty {} + +it('IntersectPick', () => { + expectTypeOf>().toEqualTypeOf<{ a: number }>() + expectTypeOf>().toEqualTypeOf<{ b: number }>() + expectTypeOf>().toEqualTypeOf() +}) From e3b3fc50f55462f571959f80226f715e18dfcd31 Mon Sep 17 00:00:00 2001 From: unnoq Date: Fri, 21 Mar 2025 13:26:37 +0700 Subject: [PATCH 5/5] fix --- packages/shared/src/types.test-d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/types.test-d.ts b/packages/shared/src/types.test-d.ts index 62d148bc3..4ca2cf2b4 100644 --- a/packages/shared/src/types.test-d.ts +++ b/packages/shared/src/types.test-d.ts @@ -17,7 +17,7 @@ it('MaybeOptionalOptions', () => { b() // @ts-expect-error - options is invalid - a({ b: '1' }) + b({ b: '1' }) b({ b: 1 }) })