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({
    	// This property shorthand
    	isAuth: { 
      		resolve: () => ({ 
      			user: 'saltyaom'
      		}) 
        }, 
        // is equivalent to
        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 而不是 throw new Error() 来标注正确的 HTTP 状态码。

如果您抛出错误,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
}) => {
} })

架构

您可以为您的宏定义一个自定义架构,以确保使用该宏的路由传递正确的类型。

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
} }) {
} })

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

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

扩展

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

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 详情,它将合并该详情,但优先保留路由的详情,而非宏的详情。