Skip to content
在 AI 工具中打开 Anthropic

宏类似于一个函数,能够对生命周期事件、模式、上下文进行控制,并具备完全的类型安全。

一旦定义,它将在钩子中可用,并且可以通过添加该属性来激活。

typescript
import { 
Elysia
} from 'elysia'
const
plugin
= new
Elysia
({
name
: 'plugin' })
.
macro
({
hi
: (
word
: string) => ({
beforeHandle
() {
console
.
log
(
word
)
} }) }) const
app
= new
Elysia
()
.
use
(
plugin
)
.
get
('/', () => 'hi', {
hi
: 'Elysia'
})

访问该路径时应记录 "Elysia"

属性简写

从 Elysia 1.2.10 开始,宏对象中的每个属性都可以是一个函数或一个对象。

如果属性是对象,它将被转换为一个接受布尔参数的函数,并且在参数为 true 时执行。

typescript
import { Elysia } from 'elysia'

export const auth = new Elysia()
    .macro({
    	// 这个属性简写
    	isAuth: { 
      		resolve: () => ({ 
      			user: 'saltyaom'
      		}) 
        }, 
        // 等价于
        isAuth(enabled: boolean) { 
        	if(!enabled) return

        	return { 
				resolve() { 
					return { 
						user 
					} 
				} 
         	} 
        } 
    })

错误处理

你可以通过返回一个 status 来返回错误的 HTTP 状态。

ts
import { Elysia, status } from 'elysia'

new Elysia()
	.macro({
		auth: {
			resolve({ headers }) {
				if(!headers.authorization)
					return status(401, 'Unauthorized') 
		
				return {
					user: 'SaltyAom'
				}
			}
		}
	})
	.get('/', ({ user }) => `Hello ${user}`, {
	            // ^?
		auth: true
	})

建议使用 return status 来标注正确的 HTTP 状态码,而不是 throw new Error()

如果你抛出错误,Elysia 默认会将其转换为 500 Internal Server Error

同样建议使用 return status 替代 throw status,以确保 EdenOpenAPI Type Gen 的类型推断正确。

解析 (Resolve)

你可以通过返回一个带有 resolve 函数的对象来为上下文添加属性。

ts
import { 
Elysia
} from 'elysia'
new
Elysia
()
.
macro
({
user
: (
enabled
: true) => ({
resolve
: () => ({
user
: 'Pardofelis'
}) }) }) .
get
('/', ({
user
}) =>
user
, {
user
: true
})

在上面的示例中,我们通过返回一个带有 resolve 函数的对象向上下文添加了一个新属性 user

以下是宏解析可能有用的几个示例:

  • 执行身份验证并将用户添加到上下文
  • 运行额外的数据库查询并将数据添加到上下文
  • 向上下文添加新属性

带有解析的宏扩展

由于 TypeScript 的限制,扩展其他宏的宏无法推断 resolve 函数的类型。

我们提供了一个命名的单一宏作为解决此限制的变通方法。

typescript
import { 
Elysia
,
t
} from 'elysia'
new
Elysia
()
.
macro
('user', {
resolve
: () => ({
user
: 'lilith' as
const
}) }) .
macro
('user2', {
user
: true,
resolve
: ({
user
}) => {
} })

模式 Schema

你可以为你的宏定义自定义模式,以确保使用宏的路由传递正确的类型。

typescript
import { 
Elysia
,
t
} from 'elysia'
new
Elysia
()
.
macro
({
withFriends
: {
body
:
t
.
Object
({
friends
:
t
.
Tuple
([
t
.
Literal
('Fouco'),
t
.
Literal
('Sartre')])
}) } }) .
post
('/', ({
body
}) =>
body
.
friends
, {
body
:
t
.
Object
({
name
:
t
.
Literal
('Lilith')
}),
withFriends
: true
})

带有模式的宏将自动进行验证和类型推断,确保类型安全,并且可以与现有模式共存。

你也可以堆叠来自不同宏的多个模式,甚至与标准验证器配合使用,它们将无缝协作。

同一宏内带生命周期的模式

类似于 带有解析的宏扩展

宏模式也支持在同一宏内的生命周期中进行类型推断但仅限于命名的单一宏,这是由于 TypeScript 的限制。

typescript
import { 
Elysia
,
t
} from 'elysia'
new
Elysia
()
.
macro
('withFriends', {
body
:
t
.
Object
({
friends
:
t
.
Tuple
([
t
.
Literal
('Fouco'),
t
.
Literal
('Sartre')])
}),
beforeHandle
({
body
: {
friends
} }) {
} })

如果你想在同一宏内使用生命周期类型推断,建议使用命名的单一宏,而非多个叠加宏。

不要将此与使用宏模式推断路由生命周期事件中的类型混淆。后者运行良好,此限制仅针对在同一宏中使用生命周期。

扩展 Extension

宏可以扩展其他宏,允许你基于已有宏进行构建。

typescript
import { 
Elysia
,
t
} from 'elysia'
new
Elysia
()
.
macro
({
sartre
: {
body
:
t
.
Object
({
sartre
:
t
.
Literal
('Sartre')
}) },
fouco
: {
body
:
t
.
Object
({
fouco
:
t
.
Literal
('Fouco')
}) },
lilith
: {
fouco
: true,
sartre
: true,
body
:
t
.
Object
({
lilith
:
t
.
Literal
('Lilith')
}) } }) .
post
('/', ({
body
}) =>
body
, {
lilith
: true
})

这允许你基于已有宏构建并为其添加更多功能。

去重

宏会自动去重生命周期事件,确保每个生命周期事件只执行一次。

默认情况下,Elysia 会使用属性值作为种子,但你也可以通过提供自定义种子来覆盖它。

typescript
import { 
Elysia
,
t
} from 'elysia'
new
Elysia
()
.
macro
({
sartre
: (
role
: string) => ({
seed
:
role
,
body
:
t
.
Object
({
sartre
:
t
.
Literal
('Sartre')
}) }) })

不过,如果你不慎创建了循环依赖,Elysia 会有一个16层的限制堆栈,以防止运行时和类型推断中出现无限循环。

如果该路由已包含 OpenAPI 细节,它将合并细节,但更优先使用路由的细节而非宏的细节。