From ef3d6af9531897b0baed6f71e4ad362ff2e0743d Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Mon, 4 Sep 2023 22:18:35 +0900 Subject: [PATCH 1/6] feat(context): introduce `c.var` --- src/context.ts | 4 + src/hono.test.ts | 229 ++++++++++++++++++++++++++++++++++++++++++++++- src/types.ts | 176 +++++++++++++++++++++++++----------- 3 files changed, 358 insertions(+), 51 deletions(-) diff --git a/src/context.ts b/src/context.ts index 5ab11451c..74cf9f25e 100644 --- a/src/context.ts +++ b/src/context.ts @@ -195,6 +195,10 @@ export class Context< return this._map ? this._map[key] : undefined } + get var(): E['Variables'] { + return this._map + } + newResponse: NewResponse = ( data: Data | null, arg?: StatusCode | ResponseInit, diff --git a/src/hono.test.ts b/src/hono.test.ts index af81ea3cc..641afdcd9 100644 --- a/src/hono.test.ts +++ b/src/hono.test.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/ban-ts-comment */ import type { Context } from './context' import { Hono } from './hono' import { HTTPException } from './http-exception' @@ -7,7 +8,7 @@ import { poweredBy } from './middleware/powered-by' import { SmartRouter } from './mod' import { RegExpRouter } from './router/reg-exp-router' import { TrieRouter } from './router/trie-router' -import type { Handler, Next } from './types' +import type { Handler, MiddlewareHandler, Next } from './types' import type { Expect, Equal } from './utils/types' import { getPath } from './utils/url' @@ -2355,3 +2356,229 @@ describe('HEAD method', () => { expect(res.body).toBe(null) }) }) + +describe('c.var - with testing types', () => { + const app = new Hono<{ + Bindings: { + Token: string + } + }>() + + const mw = + (): MiddlewareHandler<{ + Variables: { + echo: (str: string) => string + } + }> => + async (c, next) => { + c.set('echo', (str) => str) + await next() + } + + const mw2 = + (): MiddlewareHandler<{ + Variables: { + echo2: (str: string) => string + } + }> => + async (c, next) => { + c.set('echo2', (str) => str) + await next() + } + + const mw3 = + (): MiddlewareHandler<{ + Variables: { + echo3: (str: string) => string + } + }> => + async (c, next) => { + c.set('echo3', (str) => str) + await next() + } + + const mw4 = + (): MiddlewareHandler<{ + Variables: { + echo4: (str: string) => string + } + }> => + async (c, next) => { + c.set('echo4', (str) => str) + await next() + } + + const mw5 = + (): MiddlewareHandler<{ + Variables: { + echo5: (str: string) => string + } + }> => + async (c, next) => { + c.set('echo5', (str) => str) + await next() + } + + app.use('/no-path/1').get(mw(), (c) => { + return c.text(c.var.echo('hello')) + }) + + app.use('/no-path/2').get(mw(), mw2(), (c) => { + return c.text(c.var.echo('hello') + c.var.echo2('hello2')) + }) + + app.use('/no-path/3').get(mw(), mw2(), mw3(), (c) => { + return c.text(c.var.echo('hello') + c.var.echo2('hello2') + c.var.echo3('hello3')) + }) + + app.use('/no-path/4').get(mw(), mw2(), mw3(), mw4(), (c) => { + return c.text( + c.var.echo('hello') + c.var.echo2('hello2') + c.var.echo3('hello3') + c.var.echo4('hello4') + ) + }) + + app.use('/no-path/5').get(mw(), mw2(), mw3(), mw4(), mw5(), (c) => { + return c.text( + // @ts-ignore + c.var.echo('hello') + + c.var.echo2('hello2') + + c.var.echo3('hello3') + + c.var.echo4('hello4') + + c.var.echo5('hello5') + ) + }) + + app.get('/path/1', mw(), (c) => { + return c.text(c.var.echo('hello')) + }) + + app.get('/path/2', mw(), mw2(), (c) => { + return c.text(c.var.echo('hello') + c.var.echo2('hello2')) + }) + + app.get('/path/3', mw(), mw2(), mw3(), (c) => { + return c.text(c.var.echo('hello') + c.var.echo2('hello2') + c.var.echo3('hello3')) + }) + + app.get('/path/4', mw(), mw2(), mw3(), mw4(), (c) => { + return c.text( + c.var.echo('hello') + c.var.echo2('hello2') + c.var.echo3('hello3') + c.var.echo4('hello4') + ) + }) + + // @ts-expect-error + app.get('/path/5', mw(), mw2(), mw3(), mw4(), mw5(), (c) => { + return c.text( + // @ts-expect-error + c.var.echo('hello') + + // @ts-expect-error + c.var.echo2('hello2') + + // @ts-expect-error + c.var.echo3('hello3') + + // @ts-expect-error + c.var.echo4('hello4') + + // @ts-expect-error + c.var.echo5('hello5') + ) + }) + + app.on('GET', '/on/1', mw(), (c) => { + return c.text(c.var.echo('hello')) + }) + + app.on('GET', '/on/2', mw(), mw2(), (c) => { + return c.text(c.var.echo('hello') + c.var.echo2('hello2')) + }) + + app.on('GET', '/on/3', mw(), mw2(), mw3(), (c) => { + return c.text(c.var.echo('hello') + c.var.echo2('hello2') + c.var.echo3('hello3')) + }) + + app.on('GET', '/on/4', mw(), mw2(), mw3(), mw4(), (c) => { + return c.text( + c.var.echo('hello') + c.var.echo2('hello2') + c.var.echo3('hello3') + c.var.echo4('hello4') + ) + }) + + // @ts-expect-error + app.on('GET', '/on/5', mw(), mw2(), mw3(), mw4(), mw5(), (c) => { + return c.text( + // @ts-expect-error + c.var.echo('hello') + + // @ts-expect-error + c.var.echo2('hello2') + + // @ts-expect-error + c.var.echo3('hello3') + + // @ts-expect-error + c.var.echo4('hello4') + + // @ts-expect-error + c.var.echo5('hello5') + ) + }) + + it('Should return the correct response - no-path', async () => { + let res = await app.request('/no-path/1') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hello') + + res = await app.request('/no-path/2') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2') + + res = await app.request('/no-path/3') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3') + + res = await app.request('/no-path/4') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3hello4') + + res = await app.request('/no-path/5') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3hello4hello5') + }) + + it('Should return the correct response - path', async () => { + let res = await app.request('/path/1') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hello') + + res = await app.request('/path/2') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2') + + res = await app.request('/path/3') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3') + + res = await app.request('/path/4') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3hello4') + + res = await app.request('/path/5') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3hello4hello5') + }) + + it('Should return the correct response - on', async () => { + let res = await app.request('/on/1') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hello') + + res = await app.request('/on/2') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2') + + res = await app.request('/on/3') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3') + + res = await app.request('/on/4') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3hello4') + + res = await app.request('/on/5') + expect(res.status).toBe(200) + expect(await res.text()).toBe('hellohello2hello3hello4hello5') + }) +}) diff --git a/src/types.ts b/src/types.ts index d821c3d64..1e91d4d3b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -50,8 +50,9 @@ export type H< E extends Env = any, P extends string = any, I extends Input = {}, + E2 extends Env = E, R extends HandlerResponse = any -> = Handler | MiddlewareHandler +> = Handler | MiddlewareHandler export type NotFoundHandler = (c: Context) => Response | Promise export type ErrorHandler = ( @@ -77,9 +78,10 @@ export interface HandlerInterface< < P extends string = ExtractKey extends never ? BasePath : ExtractKey, I extends Input = {}, - R extends HandlerResponse = any + R extends HandlerResponse = any, + E2 extends Env = E >( - ...handlers: [H, H] + ...handlers: [H, H] ): Hono>, BasePath> // app.get(handler x 3) @@ -88,9 +90,12 @@ export interface HandlerInterface< R extends HandlerResponse = any, I extends Input = {}, I2 extends Input = I, - I3 extends Input = I & I2 + I3 extends Input = I & I2, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E >( - ...handlers: [H, H, H] + ...handlers: [H, H, H] ): Hono>, BasePath> // app.get(handler x 4) @@ -100,9 +105,18 @@ export interface HandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - I4 extends Input = I & I2 & I3 + I4 extends Input = I & I2 & I3, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E >( - ...handlers: [H, H, H, H] + ...handlers: [ + H, + H, + H, + H + ] ): Hono>, BasePath> // app.get(handler x 5) @@ -113,9 +127,20 @@ export interface HandlerInterface< I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3, - I5 extends Input = I & I2 & I3 & I4 + I5 extends Input = I & I2 & I3 & I4, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E, + E6 extends Env = E >( - ...handlers: [H, H, H, H, H] + ...handlers: [ + H, + H, + H, + H, + H + ] ): Hono>, BasePath> // app.get(...handlers[]) @@ -124,21 +149,39 @@ export interface HandlerInterface< I extends Input = {}, R extends HandlerResponse = any >( - ...handlers: Handler[] + ...handlers: H[] ): Hono>, BasePath> + //// app.get(path) + + // app.get(path) +

= any, I extends Input = {}>(path: P): Hono< + E, + S & ToSchema, I['in'], MergeTypedResponseData>, + BasePath + > + //// app.get(path, ...handlers[]) // app.get(path, handler)

= any, I extends Input = {}>( path: P, - handler: H, I, R> + handler: H, I, E, R> ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.get(path, handler, handler) -

= any, I extends Input = {}>( + < + P extends string, + R extends HandlerResponse = any, + I extends Input = {}, + E2 extends Env = {}, + E3 extends Env = {} + >( path: P, - ...handlers: [H, I, R>, H, I, R>] + ...handlers: [ + H, I, E2, R>, + H, I, E & E2, R> + ] ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.get(path, handler x3) @@ -147,13 +190,16 @@ export interface HandlerInterface< R extends HandlerResponse = any, I extends Input = {}, I2 extends Input = I, - I3 extends Input = I & I2 + I3 extends Input = I & I2, + E2 extends Env = {}, + E3 extends Env = {}, + E4 extends Env = {} >( path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E & E2 & E3, R> ] ): Hono, I3['in'], MergeTypedResponseData>, BasePath> @@ -164,14 +210,18 @@ export interface HandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - I4 extends Input = I & I2 & I3 + I4 extends Input = I & I2 & I3, + E2 extends Env = {}, + E3 extends Env = {}, + E4 extends Env = {}, + E5 extends Env = {} >( path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R>, - H, I4, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E4, R>, + H, I4, E & E2 & E3 & E4, R> ] ): Hono, I4['in'], MergeTypedResponseData>, BasePath> @@ -183,22 +233,27 @@ export interface HandlerInterface< I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3, - I5 extends Input = I & I2 & I3 & I4 + I5 extends Input = I & I2 & I3 & I4, + E2 extends Env = {}, + E3 extends Env = {}, + E4 extends Env = {}, + E5 extends Env = {}, + E6 extends Env = {} >( path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R>, - H, I4, R>, - H, I5, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E4, R>, + H, I4, E5, R>, + H, I5, E & E2 & E3 & E4 & E5, R> ] ): Hono, I5['in'], MergeTypedResponseData>, BasePath> // app.get(path, ...handlers[])

= any>( path: P, - ...handlers: H, I, R>[] + ...handlers: H, I, E, R>[] ): Hono, I['in'], MergeTypedResponseData>, BasePath> } @@ -235,10 +290,20 @@ export interface OnHandlerInterface< BasePath extends string = '/' > { // app.on(method, path, handler, handler) - = any, I extends Input = {}>( + < + M extends string, + P extends string, + R extends HandlerResponse = any, + I extends Input = {}, + E2 extends Env = E, + E3 extends Env = E + >( method: M, path: P, - ...handlers: [H, I, R>, H, I, R>] + ...handlers: [ + H, I, E2, R>, + H, I, E & E2, R> + ] ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.get(method, path, handler x3) @@ -248,17 +313,19 @@ export interface OnHandlerInterface< R extends HandlerResponse = any, I extends Input = {}, I2 extends Input = I, - I3 extends Input = I & I2 + I3 extends Input = I & I2, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E >( method: M, path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E & E2 & E3, R> ] ): Hono, I3['in'], MergeTypedResponseData>, BasePath> - // app.get(method, path, handler x4) < M extends string, @@ -267,15 +334,19 @@ export interface OnHandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - I4 extends Input = I2 & I3 + I4 extends Input = I & I2 & I3, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E >( method: M, path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R>, - H, I4, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E4, R>, + H, I4, E & E2 & E3 & E4, R> ] ): Hono, I4['in'], MergeTypedResponseData>, BasePath> @@ -287,31 +358,36 @@ export interface OnHandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - I4 extends Input = I2 & I3, - I5 extends Input = I3 & I4 + I4 extends Input = I & I2 & I3, + I5 extends Input = I & I2 & I3 & I4, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E, + E6 extends Env = E >( method: M, path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R>, - H, I4, R>, - H, I5, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E4, R>, + H, I4, E5, R>, + H, I5, E & E2 & E3 & E4 & E5, R> ] ): Hono, I5['in'], MergeTypedResponseData>, BasePath> = any, I extends Input = {}>( method: M, path: P, - ...handlers: H, I, R>[] + ...handlers: H, I, E, R>[] ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.on(method[], path, ...handler)

= any, I extends Input = {}>( methods: string[], path: P, - ...handlers: H, I, R>[] + ...handlers: H, I, E, R>[] ): Hono< E, S & ToSchema, I['in'], MergeTypedResponseData>, From a38837b63d7e7b93da66ad3aaa52e6c7ee87e2ce Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Mon, 4 Sep 2023 22:45:26 +0900 Subject: [PATCH 2/6] denoify --- deno_dist/context.ts | 4 + deno_dist/types.ts | 176 +++++++++++++++++++++++++++++++------------ 2 files changed, 130 insertions(+), 50 deletions(-) diff --git a/deno_dist/context.ts b/deno_dist/context.ts index 57329e0da..0803186ec 100644 --- a/deno_dist/context.ts +++ b/deno_dist/context.ts @@ -195,6 +195,10 @@ export class Context< return this._map ? this._map[key] : undefined } + get var(): E['Variables'] { + return this._map + } + newResponse: NewResponse = ( data: Data | null, arg?: StatusCode | ResponseInit, diff --git a/deno_dist/types.ts b/deno_dist/types.ts index de96806a3..1185e3768 100644 --- a/deno_dist/types.ts +++ b/deno_dist/types.ts @@ -50,8 +50,9 @@ export type H< E extends Env = any, P extends string = any, I extends Input = {}, + E2 extends Env = E, R extends HandlerResponse = any -> = Handler | MiddlewareHandler +> = Handler | MiddlewareHandler export type NotFoundHandler = (c: Context) => Response | Promise export type ErrorHandler = ( @@ -77,9 +78,10 @@ export interface HandlerInterface< < P extends string = ExtractKey extends never ? BasePath : ExtractKey, I extends Input = {}, - R extends HandlerResponse = any + R extends HandlerResponse = any, + E2 extends Env = E >( - ...handlers: [H, H] + ...handlers: [H, H] ): Hono>, BasePath> // app.get(handler x 3) @@ -88,9 +90,12 @@ export interface HandlerInterface< R extends HandlerResponse = any, I extends Input = {}, I2 extends Input = I, - I3 extends Input = I & I2 + I3 extends Input = I & I2, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E >( - ...handlers: [H, H, H] + ...handlers: [H, H, H] ): Hono>, BasePath> // app.get(handler x 4) @@ -100,9 +105,18 @@ export interface HandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - I4 extends Input = I & I2 & I3 + I4 extends Input = I & I2 & I3, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E >( - ...handlers: [H, H, H, H] + ...handlers: [ + H, + H, + H, + H + ] ): Hono>, BasePath> // app.get(handler x 5) @@ -113,9 +127,20 @@ export interface HandlerInterface< I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3, - I5 extends Input = I & I2 & I3 & I4 + I5 extends Input = I & I2 & I3 & I4, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E, + E6 extends Env = E >( - ...handlers: [H, H, H, H, H] + ...handlers: [ + H, + H, + H, + H, + H + ] ): Hono>, BasePath> // app.get(...handlers[]) @@ -124,21 +149,39 @@ export interface HandlerInterface< I extends Input = {}, R extends HandlerResponse = any >( - ...handlers: Handler[] + ...handlers: H[] ): Hono>, BasePath> + //// app.get(path) + + // app.get(path) +

= any, I extends Input = {}>(path: P): Hono< + E, + S & ToSchema, I['in'], MergeTypedResponseData>, + BasePath + > + //// app.get(path, ...handlers[]) // app.get(path, handler)

= any, I extends Input = {}>( path: P, - handler: H, I, R> + handler: H, I, E, R> ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.get(path, handler, handler) -

= any, I extends Input = {}>( + < + P extends string, + R extends HandlerResponse = any, + I extends Input = {}, + E2 extends Env = {}, + E3 extends Env = {} + >( path: P, - ...handlers: [H, I, R>, H, I, R>] + ...handlers: [ + H, I, E2, R>, + H, I, E & E2, R> + ] ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.get(path, handler x3) @@ -147,13 +190,16 @@ export interface HandlerInterface< R extends HandlerResponse = any, I extends Input = {}, I2 extends Input = I, - I3 extends Input = I & I2 + I3 extends Input = I & I2, + E2 extends Env = {}, + E3 extends Env = {}, + E4 extends Env = {} >( path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E & E2 & E3, R> ] ): Hono, I3['in'], MergeTypedResponseData>, BasePath> @@ -164,14 +210,18 @@ export interface HandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - I4 extends Input = I & I2 & I3 + I4 extends Input = I & I2 & I3, + E2 extends Env = {}, + E3 extends Env = {}, + E4 extends Env = {}, + E5 extends Env = {} >( path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R>, - H, I4, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E4, R>, + H, I4, E & E2 & E3 & E4, R> ] ): Hono, I4['in'], MergeTypedResponseData>, BasePath> @@ -183,22 +233,27 @@ export interface HandlerInterface< I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I2 & I3, - I5 extends Input = I & I2 & I3 & I4 + I5 extends Input = I & I2 & I3 & I4, + E2 extends Env = {}, + E3 extends Env = {}, + E4 extends Env = {}, + E5 extends Env = {}, + E6 extends Env = {} >( path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R>, - H, I4, R>, - H, I5, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E4, R>, + H, I4, E5, R>, + H, I5, E & E2 & E3 & E4 & E5, R> ] ): Hono, I5['in'], MergeTypedResponseData>, BasePath> // app.get(path, ...handlers[])

= any>( path: P, - ...handlers: H, I, R>[] + ...handlers: H, I, E, R>[] ): Hono, I['in'], MergeTypedResponseData>, BasePath> } @@ -235,10 +290,20 @@ export interface OnHandlerInterface< BasePath extends string = '/' > { // app.on(method, path, handler, handler) - = any, I extends Input = {}>( + < + M extends string, + P extends string, + R extends HandlerResponse = any, + I extends Input = {}, + E2 extends Env = E, + E3 extends Env = E + >( method: M, path: P, - ...handlers: [H, I, R>, H, I, R>] + ...handlers: [ + H, I, E2, R>, + H, I, E & E2, R> + ] ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.get(method, path, handler x3) @@ -248,17 +313,19 @@ export interface OnHandlerInterface< R extends HandlerResponse = any, I extends Input = {}, I2 extends Input = I, - I3 extends Input = I & I2 + I3 extends Input = I & I2, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E >( method: M, path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E & E2 & E3, R> ] ): Hono, I3['in'], MergeTypedResponseData>, BasePath> - // app.get(method, path, handler x4) < M extends string, @@ -267,15 +334,19 @@ export interface OnHandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - I4 extends Input = I2 & I3 + I4 extends Input = I & I2 & I3, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E >( method: M, path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R>, - H, I4, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E4, R>, + H, I4, E & E2 & E3 & E4, R> ] ): Hono, I4['in'], MergeTypedResponseData>, BasePath> @@ -287,31 +358,36 @@ export interface OnHandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - I4 extends Input = I2 & I3, - I5 extends Input = I3 & I4 + I4 extends Input = I & I2 & I3, + I5 extends Input = I & I2 & I3 & I4, + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E, + E6 extends Env = E >( method: M, path: P, ...handlers: [ - H, I, R>, - H, I2, R>, - H, I3, R>, - H, I4, R>, - H, I5, R> + H, I, E2, R>, + H, I2, E3, R>, + H, I3, E4, R>, + H, I4, E5, R>, + H, I5, E & E2 & E3 & E4 & E5, R> ] ): Hono, I5['in'], MergeTypedResponseData>, BasePath> = any, I extends Input = {}>( method: M, path: P, - ...handlers: H, I, R>[] + ...handlers: H, I, E, R>[] ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.on(method[], path, ...handler)

= any, I extends Input = {}>( methods: string[], path: P, - ...handlers: H, I, R>[] + ...handlers: H, I, E, R>[] ): Hono< E, S & ToSchema, I['in'], MergeTypedResponseData>, From 6eef21b85396fff9471409e25d8380d821083155 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Tue, 5 Sep 2023 00:13:49 +0900 Subject: [PATCH 3/6] make it a property --- src/context.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/context.ts b/src/context.ts index 74cf9f25e..72dbff59d 100644 --- a/src/context.ts +++ b/src/context.ts @@ -87,12 +87,12 @@ export class Context< > { req: HonoRequest env: E['Bindings'] = {} + var: E['Variables'] = {} finalized: boolean = false error: Error | undefined = undefined private _status: StatusCode = 200 private _exCtx: FetchEventLike | ExecutionContext | undefined // _executionCtx - private _map: Record | undefined private _h: Headers | undefined = undefined // _headers private _pH: Record | undefined = undefined // _preparedHeaders private _res: Response | undefined @@ -187,16 +187,12 @@ export class Context< } set: Set = (key: string, value: unknown) => { - this._map ||= {} - this._map[key as string] = value + this.var ??= {} + this.var[key as string] = value } get: Get = (key: string) => { - return this._map ? this._map[key] : undefined - } - - get var(): E['Variables'] { - return this._map + return this.var ? this.var[key] : undefined } newResponse: NewResponse = ( From 8695d98c56794bcbdc65eda83a05e0db5fb62919 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Tue, 5 Sep 2023 00:15:25 +0900 Subject: [PATCH 4/6] denoify --- deno_dist/context.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/deno_dist/context.ts b/deno_dist/context.ts index 0803186ec..d636a38a6 100644 --- a/deno_dist/context.ts +++ b/deno_dist/context.ts @@ -87,12 +87,12 @@ export class Context< > { req: HonoRequest env: E['Bindings'] = {} + var: E['Variables'] = {} finalized: boolean = false error: Error | undefined = undefined private _status: StatusCode = 200 private _exCtx: FetchEventLike | ExecutionContext | undefined // _executionCtx - private _map: Record | undefined private _h: Headers | undefined = undefined // _headers private _pH: Record | undefined = undefined // _preparedHeaders private _res: Response | undefined @@ -187,16 +187,12 @@ export class Context< } set: Set = (key: string, value: unknown) => { - this._map ||= {} - this._map[key as string] = value + this.var ??= {} + this.var[key as string] = value } get: Get = (key: string) => { - return this._map ? this._map[key] : undefined - } - - get var(): E['Variables'] { - return this._map + return this.var ? this.var[key] : undefined } newResponse: NewResponse = ( From c3358672340197a5e8c2452f1764b5937e514735 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Wed, 6 Sep 2023 11:10:33 +0900 Subject: [PATCH 5/6] make it a read-only --- deno_dist/context.ts | 13 +++++++++---- src/context.ts | 13 +++++++++---- src/hono.test.ts | 10 ++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/deno_dist/context.ts b/deno_dist/context.ts index dd4b28ae3..b09a8826f 100644 --- a/deno_dist/context.ts +++ b/deno_dist/context.ts @@ -94,7 +94,7 @@ export class Context< > { req: HonoRequest env: E['Bindings'] = {} - var: E['Variables'] = {} + private _var: E['Variables'] = {} finalized: boolean = false error: Error | undefined = undefined @@ -214,12 +214,17 @@ export class Context< } set: Set = (key: string, value: unknown) => { - this.var ??= {} - this.var[key as string] = value + this._var ??= {} + this._var[key as string] = value } get: Get = (key: string) => { - return this.var ? this.var[key] : undefined + return this._var ? this._var[key] : undefined + } + + // c.var.propName is a read-only + get var(): Readonly { + return { ...this._var } } newResponse: NewResponse = ( diff --git a/src/context.ts b/src/context.ts index d5b4a1fd1..f1efa78fa 100644 --- a/src/context.ts +++ b/src/context.ts @@ -94,7 +94,7 @@ export class Context< > { req: HonoRequest env: E['Bindings'] = {} - var: E['Variables'] = {} + private _var: E['Variables'] = {} finalized: boolean = false error: Error | undefined = undefined @@ -214,12 +214,17 @@ export class Context< } set: Set = (key: string, value: unknown) => { - this.var ??= {} - this.var[key as string] = value + this._var ??= {} + this._var[key as string] = value } get: Get = (key: string) => { - return this.var ? this.var[key] : undefined + return this._var ? this._var[key] : undefined + } + + // c.var.propName is a read-only + get var(): Readonly { + return { ...this._var } } newResponse: NewResponse = ( diff --git a/src/hono.test.ts b/src/hono.test.ts index a61d99560..27f20b588 100644 --- a/src/hono.test.ts +++ b/src/hono.test.ts @@ -2619,4 +2619,14 @@ describe('c.var - with testing types', () => { expect(res.status).toBe(200) expect(await res.text()).toBe('hellohello2hello3hello4hello5') }) + + it('Should be a read-only', () => { + expect(() => { + app.get('/path/1', mw(), (c) => { + // @ts-expect-error + c.var.echo = 'hello' + return c.text(c.var.echo('hello')) + }) + }).toThrow() + }) }) From 846c99967f5396680cf0dd14d3984a94235f0125 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Sat, 9 Sep 2023 00:24:58 +0900 Subject: [PATCH 6/6] fix the complex pattern --- deno_dist/types.ts | 80 ++++++++++++++++++++++++++++++---------------- src/hono.test.ts | 20 ++++++++++++ src/types.ts | 80 ++++++++++++++++++++++++++++++---------------- 3 files changed, 124 insertions(+), 56 deletions(-) diff --git a/deno_dist/types.ts b/deno_dist/types.ts index 4f932e2cf..95a3ca0f8 100644 --- a/deno_dist/types.ts +++ b/deno_dist/types.ts @@ -75,14 +75,26 @@ export interface HandlerInterface< > { //// app.get(...handlers[]) + // app.get(handler) + < + P extends string = ExtractKey extends never ? BasePath : ExtractKey, + I extends Input = {}, + R extends HandlerResponse = any, + Temp extends Env = E + >( + handler: H + ): Hono>, BasePath> + // app.get(handler, handler) < P extends string = ExtractKey extends never ? BasePath : ExtractKey, I extends Input = {}, R extends HandlerResponse = any, - E2 extends Env = E + E2 extends Env = E, + E3 extends Env = E, + Temp extends Env = E & E2 >( - ...handlers: [H, H] + ...handlers: [H, H] ): Hono>, BasePath> // app.get(handler x 3) @@ -94,9 +106,10 @@ export interface HandlerInterface< I3 extends Input = I & I2, E2 extends Env = E, E3 extends Env = E, - E4 extends Env = E + E4 extends Env = E, + Temp extends Env = E & E2 & E3 >( - ...handlers: [H, H, H] + ...handlers: [H, H, H] ): Hono>, BasePath> // app.get(handler x 4) @@ -110,13 +123,14 @@ export interface HandlerInterface< E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, - E5 extends Env = E + E5 extends Env = E, + Temp extends Env = E & E2 & E3 & E4 >( ...handlers: [ H, H, H, - H + H ] ): Hono>, BasePath> @@ -133,14 +147,15 @@ export interface HandlerInterface< E3 extends Env = E, E4 extends Env = E, E5 extends Env = E, - E6 extends Env = E + E6 extends Env = E, + Temp extends Env = E & E2 & E3 & E4 & E5 >( ...handlers: [ H, H, H, H, - H + H ] ): Hono>, BasePath> @@ -165,9 +180,14 @@ export interface HandlerInterface< //// app.get(path, ...handlers[]) // app.get(path, handler) -

= any, I extends Input = {}>( + < + P extends string, + R extends HandlerResponse = any, + I extends Input = {}, + Temp extends Env = E + >( path: P, - handler: H, I, E, R> + handler: H, I, Temp, R> ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.get(path, handler, handler) @@ -175,13 +195,14 @@ export interface HandlerInterface< P extends string, R extends HandlerResponse = any, I extends Input = {}, - E2 extends Env = {}, - E3 extends Env = {} + E2 extends Env = E, + E3 extends Env = E, + Temp extends Env = E & E2 >( path: P, ...handlers: [ H, I, E2, R>, - H, I, E & E2, R> + H, I, Temp, R> ] ): Hono, I['in'], MergeTypedResponseData>, BasePath> @@ -192,15 +213,16 @@ export interface HandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - E2 extends Env = {}, - E3 extends Env = {}, - E4 extends Env = {} + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + Temp extends Env = E & E2 & E3 >( path: P, ...handlers: [ H, I, E2, R>, H, I2, E3, R>, - H, I3, E & E2 & E3, R> + H, I3, Temp, R> ] ): Hono, I3['in'], MergeTypedResponseData>, BasePath> @@ -212,17 +234,18 @@ export interface HandlerInterface< I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I & I2 & I3, - E2 extends Env = {}, - E3 extends Env = {}, - E4 extends Env = {}, - E5 extends Env = {} + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E, + Temp extends Env = E & E2 & E3 & E4 >( path: P, ...handlers: [ H, I, E2, R>, H, I2, E3, R>, H, I3, E4, R>, - H, I4, E & E2 & E3 & E4, R> + H, I4, Temp, R> ] ): Hono, I4['in'], MergeTypedResponseData>, BasePath> @@ -235,11 +258,12 @@ export interface HandlerInterface< I3 extends Input = I & I2, I4 extends Input = I2 & I3, I5 extends Input = I & I2 & I3 & I4, - E2 extends Env = {}, - E3 extends Env = {}, - E4 extends Env = {}, - E5 extends Env = {}, - E6 extends Env = {} + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E, + E6 extends Env = E, + Temp extends Env = E & E2 & E3 & E4 & E5 >( path: P, ...handlers: [ @@ -247,7 +271,7 @@ export interface HandlerInterface< H, I2, E3, R>, H, I3, E4, R>, H, I4, E5, R>, - H, I5, E & E2 & E3 & E4 & E5, R> + H, I5, Temp, R> ] ): Hono, I5['in'], MergeTypedResponseData>, BasePath> diff --git a/src/hono.test.ts b/src/hono.test.ts index 27f20b588..8134a5ec5 100644 --- a/src/hono.test.ts +++ b/src/hono.test.ts @@ -2620,6 +2620,26 @@ describe('c.var - with testing types', () => { expect(await res.text()).toBe('hellohello2hello3hello4hello5') }) + it('Should not throw type errors', () => { + const app = new Hono<{ + Variables: { + hello: () => string + } + }>() + + app.get(mw()) + app.get(mw(), mw2()) + app.get(mw(), mw2(), mw3()) + app.get(mw(), mw2(), mw3(), mw4()) + app.get(mw(), mw2(), mw3(), mw4(), mw5()) + + app.get('/', mw()) + app.get('/', mw(), mw2()) + app.get('/', mw(), mw2(), mw3()) + app.get('/', mw(), mw2(), mw3(), mw4()) + app.get('/', mw(), mw2(), mw3(), mw4(), mw5()) + }) + it('Should be a read-only', () => { expect(() => { app.get('/path/1', mw(), (c) => { diff --git a/src/types.ts b/src/types.ts index ec9d11386..8e675ff1d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,14 +75,26 @@ export interface HandlerInterface< > { //// app.get(...handlers[]) + // app.get(handler) + < + P extends string = ExtractKey extends never ? BasePath : ExtractKey, + I extends Input = {}, + R extends HandlerResponse = any, + Temp extends Env = E + >( + handler: H + ): Hono>, BasePath> + // app.get(handler, handler) < P extends string = ExtractKey extends never ? BasePath : ExtractKey, I extends Input = {}, R extends HandlerResponse = any, - E2 extends Env = E + E2 extends Env = E, + E3 extends Env = E, + Temp extends Env = E & E2 >( - ...handlers: [H, H] + ...handlers: [H, H] ): Hono>, BasePath> // app.get(handler x 3) @@ -94,9 +106,10 @@ export interface HandlerInterface< I3 extends Input = I & I2, E2 extends Env = E, E3 extends Env = E, - E4 extends Env = E + E4 extends Env = E, + Temp extends Env = E & E2 & E3 >( - ...handlers: [H, H, H] + ...handlers: [H, H, H] ): Hono>, BasePath> // app.get(handler x 4) @@ -110,13 +123,14 @@ export interface HandlerInterface< E2 extends Env = E, E3 extends Env = E, E4 extends Env = E, - E5 extends Env = E + E5 extends Env = E, + Temp extends Env = E & E2 & E3 & E4 >( ...handlers: [ H, H, H, - H + H ] ): Hono>, BasePath> @@ -133,14 +147,15 @@ export interface HandlerInterface< E3 extends Env = E, E4 extends Env = E, E5 extends Env = E, - E6 extends Env = E + E6 extends Env = E, + Temp extends Env = E & E2 & E3 & E4 & E5 >( ...handlers: [ H, H, H, H, - H + H ] ): Hono>, BasePath> @@ -165,9 +180,14 @@ export interface HandlerInterface< //// app.get(path, ...handlers[]) // app.get(path, handler) -

= any, I extends Input = {}>( + < + P extends string, + R extends HandlerResponse = any, + I extends Input = {}, + Temp extends Env = E + >( path: P, - handler: H, I, E, R> + handler: H, I, Temp, R> ): Hono, I['in'], MergeTypedResponseData>, BasePath> // app.get(path, handler, handler) @@ -175,13 +195,14 @@ export interface HandlerInterface< P extends string, R extends HandlerResponse = any, I extends Input = {}, - E2 extends Env = {}, - E3 extends Env = {} + E2 extends Env = E, + E3 extends Env = E, + Temp extends Env = E & E2 >( path: P, ...handlers: [ H, I, E2, R>, - H, I, E & E2, R> + H, I, Temp, R> ] ): Hono, I['in'], MergeTypedResponseData>, BasePath> @@ -192,15 +213,16 @@ export interface HandlerInterface< I extends Input = {}, I2 extends Input = I, I3 extends Input = I & I2, - E2 extends Env = {}, - E3 extends Env = {}, - E4 extends Env = {} + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + Temp extends Env = E & E2 & E3 >( path: P, ...handlers: [ H, I, E2, R>, H, I2, E3, R>, - H, I3, E & E2 & E3, R> + H, I3, Temp, R> ] ): Hono, I3['in'], MergeTypedResponseData>, BasePath> @@ -212,17 +234,18 @@ export interface HandlerInterface< I2 extends Input = I, I3 extends Input = I & I2, I4 extends Input = I & I2 & I3, - E2 extends Env = {}, - E3 extends Env = {}, - E4 extends Env = {}, - E5 extends Env = {} + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E, + Temp extends Env = E & E2 & E3 & E4 >( path: P, ...handlers: [ H, I, E2, R>, H, I2, E3, R>, H, I3, E4, R>, - H, I4, E & E2 & E3 & E4, R> + H, I4, Temp, R> ] ): Hono, I4['in'], MergeTypedResponseData>, BasePath> @@ -235,11 +258,12 @@ export interface HandlerInterface< I3 extends Input = I & I2, I4 extends Input = I2 & I3, I5 extends Input = I & I2 & I3 & I4, - E2 extends Env = {}, - E3 extends Env = {}, - E4 extends Env = {}, - E5 extends Env = {}, - E6 extends Env = {} + E2 extends Env = E, + E3 extends Env = E, + E4 extends Env = E, + E5 extends Env = E, + E6 extends Env = E, + Temp extends Env = E & E2 & E3 & E4 & E5 >( path: P, ...handlers: [ @@ -247,7 +271,7 @@ export interface HandlerInterface< H, I2, E3, R>, H, I3, E4, R>, H, I4, E5, R>, - H, I5, E & E2 & E3 & E4 & E5, R> + H, I5, Temp, R> ] ): Hono, I5['in'], MergeTypedResponseData>, BasePath>