Skip to content
我们的赞助商

从 Hono 迁移到 Elysia

本指南面向希望了解 Elysia 与 Hono 差异(包括语法)的 Hono 用户,并通过示例说明如何将应用从 Hono 迁移至 Elysia。

Hono 是一个基于 Web 标准构建的快速轻量级框架。它对多种运行时(如 Deno、Bun、Cloudflare Workers 和 Node.js)具有广泛的兼容性。

Elysia 是一个符合人体工学的 Web 框架。设计注重健全的类型安全和性能,旨在提供符合人体工学和开发者友好的体验。

两个框架都构建在 Web 标准 API 之上,语法略有不同。Hono 提供与多种运行时的更广泛兼容性,而 Elysia 专注于特定的一组运行时。

性能

得益于静态代码分析,Elysia 相比 Hono 有显著的性能提升。

  1. Elysia
    1,837,294 reqs/s
  2. Hono

    740,451

以每秒请求数测量。结果来自 TechEmpower 基准测试 第 23 轮(2025-02-24)中的 JSON 序列化

路由

Hono 和 Elysia 具有相似的路由语法,使用 app.get()app.post() 方法定义路由,以及相似的路径参数语法。

两者都使用单一的 Context 参数处理请求和响应,并直接返回响应。

ts
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => {
    return c.text('Hello World')
})

app.post('/id/:id', (c) => {
	c.status(201)
    return c.text(req.params.id)
})

export default app

Hono 使用辅助函数 c.textc.json 返回响应

ts
import { Elysia } from 'elysia'

const app = new Elysia()
    .get('/', 'Hello World')
    .post(
    	'/id/:id',
     	({ status, params: { id } }) => {
      		return status(201, id)
      	}
    )
    .listen(3000)

Elysia 使用单一的 context 并直接返回响应

Hono 使用 c.textc.json 包装响应,而 Elysia 自动将值映射为响应。

风格指南略有不同,Elysia 推荐使用方法链和对象解构。

Hono 的端口分配取决于运行时和适配器,而 Elysia 使用单一的 listen 方法启动服务器。

处理程序

Hono 使用函数手动解析查询、头部和请求体,而 Elysia 自动解析属性。

ts
import { Hono } from 'hono'

const app = new Hono()

app.post('/user', async (c) => {
	const limit = c.req.query('limit')
    const { name } = await c.body()
    const auth = c.req.header('authorization')

    return c.json({ limit, name, auth })
})

Hono 自动解析请求体,但不适用于查询和头部

ts
import { Elysia } from 'elysia'

const app = new Elysia()
	.post('/user', (ctx) => {
	    const limit = ctx.query.limit
	    const name = ctx.body.name
	    const auth = ctx.headers.authorization

	    return { limit, name, auth }
	})

Elysia 使用静态代码分析来确定需要解析的内容

Elysia 使用静态代码分析来确定需要解析的内容,并且只解析必需的属性。

这对性能和类型安全都有好处。

子路由

两者都可以继承另一个实例作为路由,但 Elysia 将每个实例视为一个组件,可用作子路由。

ts
import { Hono } from 'hono'

const subRouter = new Hono()

subRouter.get('/user', (c) => {
	return c.text('Hello User')
})

const app = new Hono()

app.route('/api', subRouter)

Hono 需要前缀来分隔子路由

ts
import { Elysia } from 'elysia'

const subRouter = new Elysia({ prefix: '/api' })
	.get('/user', 'Hello User')

const app = new Elysia()
	.use(subRouter)

Elysia 使用可选的前缀构造函数来定义

Hono 需要前缀来分隔子路由,而 Elysia 不需要前缀来分隔子路由。

验证

Hono 通过外部包支持各种验证器,而 Elysia 内置了使用 TypeBox 的验证,并支持开箱即用的标准模式,允许您使用喜欢的库(如 Zod、Valibot、ArkType、Effect Schema 等)而无需额外库。Elysia 还提供与 OpenAPI 的无缝集成,并在幕后进行类型推断。

ts
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

const app = new Hono()

app.patch(
	'/user/:id',
	zValidator(
		'param',
		z.object({
			id: z.coerce.number()
		})
	),
	zValidator(
		'json',
		z.object({
			name: z.string()
		})
	),
	(c) => {
		return c.json({
			params: c.req.param(),
			body: c.req.json()
		})
	}
)

Hono 使用基于管道的验证

ts
import { 
Elysia
,
t
} from 'elysia'
const
app
= new
Elysia
()
.
patch
('/user/:id', ({
params
,
body
}) => ({
params
,
body
}), {
params
:
t
.
Object
({
id
:
t
.
Number
()
}),
body
:
t
.
Object
({
name
:
t
.
String
()
}) })
ts
import { 
Elysia
} from 'elysia'
import {
z
} from 'zod'
const
app
= new
Elysia
()
.
patch
('/user/:id', ({
params
,
body
}) => ({
params
,
body
}), {
params
:
z
.
object
({
id
:
z
.
number
()
}),
body
:
z
.
object
({
name
:
z
.
string
()
}) })
ts
import { 
Elysia
} from 'elysia'
import * as
v
from 'zod'
const
app
= new
Elysia
()
.
patch
('/user/:id', ({
params
,
body
}) => ({
params
,
body
}), {
params
:
v
.
object
({
id
:
v
.
number
()
}),
body
:
v
.
object
({
name
:
v
.
string
()
}) })

Elysia 使用 TypeBox 进行验证,并自动强制类型转换。同时支持各种验证库,如 Zod、Valibot,语法相同。

两者都提供从模式到上下文的自动类型推断。

文件上传

Hono 和 Elysia 都使用 Web 标准 API 处理文件上传,但 Elysia 内置了使用 file-type 验证 mimetype 的声明式文件验证支持。

ts
import { Hono } from 'hono'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'

import { fileTypeFromBlob } from 'file-type'

const app = new Hono()

app.post(
	'/upload',
	zValidator(
		'form',
		z.object({
			file: z.instanceof(File)
		})
	),
	async (c) => {
		const body = await c.req.parseBody()

		const type = await fileTypeFromBlob(body.image as File)
		if (!type || !type.mime.startsWith('image/')) {
			c.status(422)
			return c.text('File is not a valid image')
		}

		return new Response(body.image)
	}
)

Hono 需要单独的 file-type 库来验证 mimetype

ts
import { Elysia, t } from 'elysia'

const app = new Elysia()
	.post('/upload', ({ body }) => body.file, {
		body: t.Object({
			file: t.File({
				type: 'image'
			})
		})
	})

Elysia 以声明方式处理文件和 mimetype 验证

由于 Web 标准 API 不验证 mimetype,信任客户端提供的 content-type 存在安全风险,因此 Hono 需要外部库,而 Elysia 使用 file-type 自动验证 mimetype。

中间件

Hono 中间件使用类似于 Express 的单一基于队列的顺序,而 Elysia 使用基于事件的生命周期为您提供更精细的控制。

Elysia 的生命周期事件可以如下图所示。 Elysia 生命周期图

点击图片放大

Hono 具有单一顺序的请求管道流程,而 Elysia 可以拦截请求管道中的每个事件。

ts
import { Hono } from 'hono'

const app = new Hono()

// 全局中间件
app.use(async (c, next) => {
	console.log(`${c.method} ${c.url}`)

	await next()
})

app.get(
	'/protected',
	// 路由特定中间件
	async (c, next) => {
	  	const token = c.headers.authorization

	  	if (!token) {
			c.status(401)
	   		return c.text('Unauthorized')
		}

	  	await next()
	},
	(req, res) => {
  		res.send('Protected route')
	}
)

Hono 使用单一基于队列的顺序执行中间件

ts
import { Elysia } from 'elysia'

const app = new Elysia()
	// 全局中间件
	.onRequest(({ method, path }) => {
		console.log(`${method} ${path}`)
	})
	// 路由特定中间件
	.get('/protected', () => 'protected', {
		beforeHandle({ status, headers }) {
  			if (!headers.authorizaton)
     			return status(401)
		}
	})

Elysia 使用特定事件拦截器处理请求管道中的每个点

Hono 有 next 函数调用下一个中间件,而 Elysia 没有。

健全的类型安全

Elysia 设计为具有健全的类型安全。

例如,您可以使用 deriveresolve类型安全的方式自定义上下文,而 Hono 不能。

ts
import { 
Hono
} from 'hono'
import {
createMiddleware
} from 'hono/factory'
const
app
= new
Hono
()
const
getVersion
=
createMiddleware
(async (
c
,
next
) => {
c
.
set
('version', 2)
await
next
()
})
app
.
use
(
getVersion
)
app
.
get
('/version',
getVersion
, (
c
) => {
return
c
.
text
(
c
.
get
('version') + '')
No overload matches this call. Overload 1 of 2, '(key: never): unknown', gave the following error. Argument of type '"version"' is not assignable to parameter of type 'never'. Overload 2 of 2, '(key: never): never', gave the following error. Argument of type '"version"' is not assignable to parameter of type 'never'.
}) const
authenticate
=
createMiddleware
(async (
c
,
next
) => {
const
token
=
c
.
req
.
header
('authorization')
if (!
token
) {
c
.
status
(401)
return
c
.
text
('Unauthorized')
}
c
.
set
('token',
token
.
split
(' ')[1])
await
next
()
})
app
.
post
('/user',
authenticate
, async (
c
) => {
c
.
get
('version')
No overload matches this call. Overload 1 of 2, '(key: never): unknown', gave the following error. Argument of type '"version"' is not assignable to parameter of type 'never'. Overload 2 of 2, '(key: never): never', gave the following error. Argument of type '"version"' is not assignable to parameter of type 'never'.
return
c
.
text
(c.get('token'))
No overload matches this call. Overload 1 of 2, '(key: never): unknown', gave the following error. Argument of type '"token"' is not assignable to parameter of type 'never'. Overload 2 of 2, '(key: never): never', gave the following error. Argument of type '"token"' is not assignable to parameter of type 'never'.
No overload matches this call. Overload 1 of 2, '(text: string, status?: ContentfulStatusCode | undefined, headers?: HeaderRecord | undefined): Response & TypedResponse<string, ContentfulStatusCode, "text">', gave the following error. Argument of type 'unknown' is not assignable to parameter of type 'string'. Overload 2 of 2, '(text: string, init?: ResponseOrInit<ContentfulStatusCode> | undefined): Response & TypedResponse<string, ContentfulStatusCode, "text">', gave the following error. Argument of type 'unknown' is not assignable to parameter of type 'string'.
})

Hono 使用中间件扩展上下文,但不是类型安全的

ts
import { 
Elysia
} from 'elysia'
const
app
= new
Elysia
()
.
decorate
('version', 2)
.
get
('/version', ({
version
}) =>
version
)
.
resolve
(({
status
,
headers
: {
authorization
} }) => {
if(!
authorization
?.
startsWith
('Bearer '))
return
status
(401)
return {
token
:
authorization
.
split
(' ')[1]
} }) .
get
('/token', ({
token
,
version
}) => {
version
return
token
})

Elysia 使用特定事件拦截器处理请求管道中的每个点

虽然 Hono 可以使用 declare module 扩展 ContextVariableMap 接口,但它是全局可用的,不具备健全的类型安全,并且不保证属性在所有请求处理程序中可用。

ts
declare module 'hono' {
  	interface ContextVariableMap {
    	version: number
  		token: string
  	}
}

上述 Hono 示例需要此声明才能工作,但这不提供健全的类型安全

中间件参数

Hono 使用回调函数定义可重用的路由特定中间件,而 Elysia 使用 macro 定义自定义钩子。

ts
import { 
Hono
} from 'hono'
import {
createMiddleware
} from 'hono/factory'
const
app
= new
Hono
()
const
role
= (
role
: 'user' | 'admin') =>
createMiddleware
(async (
c
,
next
) => {
const
user
=
findUser
(
c
.
req
.
header
('Authorization'))
if(
user
.
role
!==
role
) {
c
.
status
(401)
return
c
.
text
('Unauthorized')
}
c
.
set
('user',
user
)
await
next
()
})
app
.
get
('/user/:id',
role
('admin'), (
c
) => {
return c.json(c.get('user'))
No overload matches this call. Overload 1 of 2, '(key: never): unknown', gave the following error. Argument of type '"user"' is not assignable to parameter of type 'never'. Overload 2 of 2, '(key: never): never', gave the following error. Argument of type '"user"' is not assignable to parameter of type 'never'.
No overload matches this call. Overload 1 of 2, '(object: JSONValue | {} | InvalidJSONValue, status?: ContentfulStatusCode | undefined, headers?: HeaderRecord | undefined): JSONRespondReturn<...>', gave the following error. Argument of type 'unknown' is not assignable to parameter of type 'JSONValue | {} | InvalidJSONValue'. Overload 2 of 2, '(object: JSONValue | {} | InvalidJSONValue, init?: ResponseOrInit<ContentfulStatusCode> | undefined): JSONRespondReturn<...>', gave the following error. Argument of type 'unknown' is not assignable to parameter of type 'JSONValue | {} | InvalidJSONValue'.
Type instantiation is excessively deep and possibly infinite.
})

Hono 使用回调返回 createMiddleware 创建可重用中间件,但不是类型安全的

ts
import { 
Elysia
} from 'elysia'
const
app
= new
Elysia
()
.
macro
({
role
: (
role
: 'user' | 'admin') => ({
resolve
({
status
,
headers
: {
authorization
} }) {
const
user
=
findUser
(
authorization
)
if(
user
.
role
!==
role
)
return
status
(401)
return {
user
} } }) }) .
get
('/token', ({
user
}) =>
user
, {
role
: 'admin'
})

Elysia 使用宏将自定义参数传递给自定义中间件

错误处理

Hono 提供一个适用于所有路由的 onError 函数,而 Elysia 提供更精细的错误处理控制。

ts
import { Hono } from 'hono'

const app = new Hono()

class CustomError extends Error {
	constructor(message: string) {
		super(message)
		this.name = 'CustomError'
	}
}

// 全局错误处理程序
app.onError((error, c) => {
	if(error instanceof CustomError) {
		c.status(500)

		return c.json({
			message: 'Something went wrong!',
			error
		})
	}
})

// 路由特定错误处理程序
app.get('/error', (req, res) => {
	throw new CustomError('oh uh')
})

Hono 使用 onError 函数处理错误,所有路由共用单一错误处理程序

ts
import { 
Elysia
} from 'elysia'
class
CustomError
extends
Error
{
// 可选:自定义 HTTP 状态码
status
= 500
constructor(
message
: string) {
super(
message
)
this.
name
= 'CustomError'
} // 可选:发送给客户端的内容
toResponse
() {
return {
message
: "If you're seeing this, our dev forgot to handle this error",
error
: this
} } } const
app
= new
Elysia
()
// 可选:注册自定义错误类 .
error
({
CUSTOM
:
CustomError
,
}) // 全局错误处理程序 .
onError
(({
error
,
code
}) => {
if(
code
=== 'CUSTOM')
return {
message
: 'Something went wrong!',
error
} }) .
get
('/error', () => {
throw new
CustomError
('oh uh')
}, { // 可选:路由特定错误处理程序
error
({
error
}) {
return {
message
: 'Only for this route!',
error
} } })

Elysia 提供更精细的错误控制和作用域机制

Hono 提供类似中间件的错误处理,而 Elysia 提供:

  1. 全局和路由特定的错误处理程序
  2. 映射 HTTP 状态和 toResponse 的简写方式,用于将错误映射到响应
  3. 为每个错误提供自定义错误代码

错误代码对日志记录和调试很有用,并且在区分扩展自同一类的不同错误类型时很重要。

封装

Hono 封装插件的副作用,而 Elysia 通过显式的作用域机制和代码顺序控制插件的副作用。

ts
import { Hono } from 'hono'

const subRouter = new Hono()

subRouter.get('/user', (c) => {
	return c.text('Hello User')
})

const app = new Hono()

app.route('/api', subRouter)

Hono 封装插件的副作用

ts
import { Elysia } from 'elysia'

const subRouter = new Elysia()
	.onBeforeHandle(({ status, headers: { authorization } }) => {
		if(!authorization?.startsWith('Bearer '))
			return status(401)
   	})

const app = new Elysia()
    .get('/', 'Hello World')
    .use(subRouter)
    // 没有来自 subRouter 的副作用
    .get('/side-effect', () => 'hi')

Elysia 封装插件的副作用,除非明确声明

两者都有插件的封装机制以防止副作用。

然而,Elysia 可以通过声明作用域来明确哪些插件应该有副作用,而 Fastify 总是封装它。

ts
import { Elysia } from 'elysia'

const subRouter = new Elysia()
	.onBeforeHandle(({ status, headers: { authorization } }) => {
		if(!authorization?.startsWith('Bearer '))
			return status(401)
   	})
	// 作用域限定于父实例但不超出范围
	.as('scoped') 

const app = new Elysia()
    .get('/', 'Hello World')
    .use(subRouter)
    // 现在有来自 subRouter 的副作用
    .get('/side-effect', () => 'hi')

Elysia 提供 3 种作用域机制:

  1. local - 仅应用于当前实例,无副作用(默认)
  2. scoped - 副作用作用域限定于父实例但不超出范围
  3. global - 影响所有实例

由于 Hono 不提供作用域机制,我们需要:

  1. 为每个钩子创建函数并手动附加
  2. 使用高阶函数,并将其应用于需要效果的实例

但是,如果不小心处理,可能会导致重复的副作用。

ts
import { Hono } from 'hono'
import { createMiddleware } from 'hono/factory'

const middleware = createMiddleware(async (c, next) => {
	console.log('called')

	await next()
})

const app = new Hono()
const subRouter = new Hono()

app.use(middleware)
app.get('/main', (c) => c.text('Hello from main!'))

subRouter.use(middleware)

// 这会记录两次
subRouter.get('/sub', (c) => c.text('Hello from sub router!'))

app.route('/sub', subRouter)

export default app

在这种情况下,Elysia 提供插件去重机制以防止重复的副作用。

ts
import { Elysia } from 'elysia'

const subRouter = new Elysia({ name: 'subRouter' }) 
	.onBeforeHandle(({ status, headers: { authorization } }) => {
		if(!authorization?.startsWith('Bearer '))
			return status(401)
   	})
	.as('scoped')

const app = new Elysia()
	.get('/', 'Hello World')
	.use(subRouter)
	.use(subRouter) 
	.use(subRouter) 
	.use(subRouter) 
	// 副作用只调用一次
	.get('/side-effect', () => 'hi')

通过使用唯一的 name,Elysia 只会应用插件一次,不会导致重复的副作用。

Hono 在 hono/cookie 下有内置的 cookie 实用函数,而 Elysia 使用基于信号的方法处理 cookie。

ts
import { Hono } from 'hono'
import { getSignedCookie, setSignedCookie } from 'hono/cookie'

const app = new Hono()

app.get('/', async (c) => {
	const name = await getSignedCookie(c, 'secret', 'name')

	await setSignedCookie(
		c,
		'name',
		'value',
		'secret',
		{
			maxAge: 1000,
		}
	)
})

Hono 使用实用函数处理 cookie

ts
import { Elysia } from 'elysia'

const app = new Elysia({
	cookie: {
		secret: 'secret'
	}
})
	.get('/', ({ cookie: { name } }) => {
		// 签名验证自动处理
		name.value

		// cookie 签名自动签名
		name.value = 'value'
		name.maxAge = 1000 * 60 * 60 * 24
	})

Elysia 使用基于信号的方法处理 cookie

OpenAPI

Hono 需要额外努力来描述规范,而 Elysia 将规范无缝集成到模式中。

ts
import { Hono } from 'hono'
import { describeRoute, openAPISpecs } from 'hono-openapi'
import { resolver, validator as zodValidator } from 'hono-openapi/zod'
import { swaggerUI } from '@hono/swagger-ui'

import { z } from '@hono/zod-openapi'

const app = new Hono()

const model = z.array(
	z.object({
		name: z.string().openapi({
			description: 'first name only'
		}),
		age: z.number()
	})
)

const detail = await resolver(model).builder()

console.log(detail)

app.post(
	'/',
	zodValidator('json', model),
	describeRoute({
		validateResponse: true,
		summary: 'Create user',
		requestBody: {
			content: {
				'application/json': { schema: detail.schema }
			}
		},
		responses: {
			201: {
				description: 'User created',
				content: {
					'application/json': { schema: resolver(model) }
				}
			}
		}
	}),
	(c) => {
		c.status(201)
		return c.json(c.req.valid('json'))
	}
)

app.get('/ui', swaggerUI({ url: '/doc' }))

app.get(
	'/doc',
	openAPISpecs(app, {
		documentation: {
			info: {
				title: 'Hono API',
				version: '1.0.0',
				description: 'Greeting API'
			},
			components: {
				...detail.components
			}
		}
	})
)

export default app

Hono 需要额外努力来描述规范

ts
import { 
Elysia
,
t
} from 'elysia'
import {
openapi
} from '@elysiajs/openapi'
const
app
= new
Elysia
()
.
use
(
openapi
())
.
model
({
user
:
t
.
Array
(
t
.
Object
({
name
:
t
.
String
(),
age
:
t
.
Number
()
}) ) }) .
post
('/users', ({
body
}) =>
body
, {
body
: 'user',
response
: {
201: 'user' },
detail
: {
summary
: 'Create user'
} })

Elysia 将规范无缝集成到模式中

Hono 有单独的函数来描述路由规范、验证,并且需要一些努力来正确设置。

Elysia 使用您提供的模式生成 OpenAPI 规范,并验证请求/响应,并从单一事实来源自动推断类型。

Elysia 还将 model 中注册的模式附加到 OpenAPI 规范中,允许您在 Swagger 或 Scalar UI 的专用部分引用模型,而 Hono 将模式内联到路由中。

测试

两者都构建在 Web 标准 API 之上,允许与任何测试库一起使用。

ts
import { Hono } from 'hono'
import { describe, it, expect } from 'vitest'

const app = new Hono()
	.get('/', (c) => c.text('Hello World'))

describe('GET /', () => {
	it('should return Hello World', async () => {
		const res = await app.request('/')

		expect(res.status).toBe(200)
		expect(await res.text()).toBe('Hello World')
	})
})

Hono 有内置的 request 方法来运行请求

ts
import { Elysia } from 'elysia'
import { describe, it, expect } from 'vitest'

const app = new Elysia()
	.get('/', 'Hello World')

describe('GET /', () => {
	it('should return Hello World', async () => {
		const res = await app.handle(
			new Request('http://localhost')
		)

		expect(res.status).toBe(200)
		expect(await res.text()).toBe('Hello World')
	})
})

Elysia 使用 Web 标准 API 处理请求和响应

或者,Elysia 还提供了一个名为 Eden 的辅助库,用于端到端类型安全,允许我们进行自动完成和完全类型安全的测试。

ts
import { 
Elysia
} from 'elysia'
import {
treaty
} from '@elysiajs/eden'
import {
describe
,
expect
,
it
} from 'bun:test'
const
app
= new
Elysia
().
get
('/hello', 'Hello World')
const
api
=
treaty
(
app
)
describe
('GET /', () => {
it
('should return Hello World', async () => {
const {
data
,
error
,
status
} = await
api
.
hello
.
get
()
expect
(
status
).
toBe
(200)
expect
(
data
).
toBe
('Hello World')
}) })

端到端类型安全

两者都提供端到端类型安全,但 Hono 似乎不提供基于状态码的类型安全错误处理。

ts
import { 
Hono
} from 'hono'
import {
hc
} from 'hono/client'
import {
z
} from 'zod'
import {
zValidator
} from '@hono/zod-validator'
const
app
= new
Hono
()
.
post
(
'/mirror',
zValidator
(
'json',
z
.
object
({
message
:
z
.
string
()
}) ), (
c
) =>
c
.
json
(
c
.
req
.
valid
('json'))
) const
client
=
hc
<typeof
app
>('/')
const
response
= await
client
.
mirror
.
$post
({
json
: {
message
: 'Hello, world!'
} }) const
data
= await
response
.
json
()
console
.
log
(
data
)

Hono 使用 hc 运行请求,并提供端到端类型安全

ts
import { 
Elysia
,
t
} from 'elysia'
import {
treaty
} from '@elysiajs/eden'
const
app
= new
Elysia
()
.
post
('/mirror', ({
body
}) =>
body
, {
body
:
t
.
Object
({
message
:
t
.
String
()
}) }) const
api
=
treaty
(
app
)
const {
data
,
error
} = await
api
.
mirror
.
post
({
message
: 'Hello World'
}) if(
error
)
throw
error
console
.
log
(
data
)

Elysia 使用 treaty 运行请求,并提供端到端类型安全

虽然两者都提供端到端类型安全,但 Elysia 提供基于状态码的更类型安全的错误处理,而 Hono 没有。

使用相同目的的代码测量每个框架的类型推断速度,Elysia 的类型检查速度比 Hono 快 2.3 倍。

Elysia eden 类型推断性能

Elysia 推断 Elysia 和 Eden 耗时 536ms(点击放大)

Hono HC 类型推断性能

Hono 推断 Hono 和 HC 耗时 1.27 秒,出现错误(中止)(点击放大)

1.27 秒并不反映推断的整个持续时间,而是从开始到因错误中止的持续时间 "Type instantiation is excessively deep and possibly infinite.",当模式过大时会发生此错误。

Hono HC 代码显示 excessively deep 错误

Hono HC 显示 excessively deep 错误

这是由于大型模式导致的,Hono 不支持超过 100 个具有复杂请求体和响应验证的路由,而 Elysia 没有这个问题。

Elysia Eden 代码显示无错误的类型推断

Elysia Eden 代码显示无错误的类型推断

Elysia 具有更快的类型推断性能,并且至少在 2,000 个具有复杂请求体和响应验证的路由上不会出现 "Type instantiation is excessively deep and possibly infinite." 错误。

如果端到端类型安全对您很重要,那么 Elysia 是正确的选择。


两者都是构建在 Web 标准 API 之上的下一代 Web 框架,略有不同。

Elysia 设计为符合人体工学和开发者友好,注重健全的类型安全,并且比 Hono 有更好的性能。

而 Hono 提供与多种运行时的广泛兼容性,尤其是 Cloudflare Workers,并且用户群更大。

或者,如果您来自不同的框架,可以查看: