Skip to content
我们的赞助商

Eden 安装

首先在前端安装 Eden:

bash
bun add @elysiajs/eden
bun add -d elysia

TIP

Eden 需要 Elysia 来推断实用工具类型。

请确保安装的 Elysia 版本与服务器匹配。

首先,导出您现有的 Elysia 服务器类型:

typescript
// server.ts
import { Elysia, t } from 'elysia'

const app = new Elysia()
    .get('/', () => 'Hi Elysia')
    .get('/id/:id', ({ params: { id } }) => id)
    .post('/mirror', ({ body }) => body, {
        body: t.Object({
            id: t.Number(),
            name: t.String()
        })
    })
    .listen(3000)

export type App = typeof app 

然后在客户端消费 Elysia API:

typescript
// client.ts
import { 
treaty
} from '@elysiajs/eden'
import type {
App
} from './server'
const
client
=
treaty
<
App
>('localhost:3000')
// response: Hi Elysia const {
data
:
index
} = await
client
.
get
()
// response: 1895 const {
data
:
id
} = await
client
.
id
({
id
: 1895 }).
get
()
// response: { id: 1895, name: 'Skadi' } const {
data
:
nendoroid
} = await
client
.
mirror
.
post
({
id
: 1895,
name
: 'Skadi'
})
client
.

注意事项

有时,Eden 可能无法正确从 Elysia 推断类型,以下是最常见的解决 Eden 类型推断问题的变通方法。

类型严格模式

请确保在 tsconfig.json 中启用严格模式

json
{
  "compilerOptions": {
    "strict": true
  }
}

Elysia 版本不匹配

Eden 依赖 Elysia 类来导入 Elysia 实例并正确推断类型。

请确保客户端和服务器具有匹配的 Elysia 版本。

您可以使用 npm why 命令检查它:

bash
npm why elysia

输出应仅包含一个顶级 elysia 版本:

elysia@1.1.12
node_modules/elysia
  elysia@"1.1.25" from the root project
  peer elysia@">= 1.1.0" from @elysiajs/html@1.1.0
  node_modules/@elysiajs/html
    dev @elysiajs/html@"1.1.1" from the root project
  peer elysia@">= 1.1.0" from @elysiajs/opentelemetry@1.1.2
  node_modules/@elysiajs/opentelemetry
    dev @elysiajs/opentelemetry@"1.1.7" from the root project
  peer elysia@">= 1.1.0" from @elysiajs/swagger@1.1.0
  node_modules/@elysiajs/swagger
    dev @elysiajs/swagger@"1.1.6" from the root project
  peer elysia@">= 1.1.0" from @elysiajs/eden@1.1.2
  node_modules/@elysiajs/eden
    dev @elysiajs/eden@"1.1.3" from the root project

TypeScript 版本

Elysia 使用 TypeScript 的较新功能和语法,以最性能的方式推断类型。诸如 Const Generic 和 Template Literal 等功能被大量使用。

请确保您的客户端具有 最低 TypeScript 版本 >= 5.0

方法链

为了使 Eden 工作,Elysia 必须使用 方法链

Elysia 的类型系统很复杂,方法通常会为实例引入新类型。

使用方法链将有助于保存该新类型引用。

例如:

typescript
import { 
Elysia
} from 'elysia'
new
Elysia
()
.
state
('build', 1)
// Store is strictly typed .
get
('/', ({
store
: {
build
} }) =>
build
)
.
listen
(3000)

使用此方法,state 现在返回一个新的 ElysiaInstance 类型,将 build 引入 store 以替换当前类型。

不使用方法链时,Elysia 在引入新类型时不会保存它,导致无法进行类型推断。

typescript
import { 
Elysia
} from 'elysia'
const
app
= new
Elysia
()
app
.
state
('build', 1)
app
.
get
('/', ({
store
: { build } }) =>
build
)
Property 'build' does not exist on type '{}'.
app
.
listen
(3000)

类型定义

如果您使用 Bun 特定功能,如 Bun.file 或类似 API 并从处理程序中返回它,您可能需要将 Bun 类型定义安装到客户端。

bash
bun add -d @types/bun

路径别名(monorepo)

如果您在 monorepo 中使用路径别名,请确保前端能够像后端一样解析路径。

TIP

在 monorepo 中设置路径别名有点棘手,您可以 fork 我们的示例模板:Kozeki Template 并根据您的需求修改它。

例如,如果您的后端在 tsconfig.json 中有以下路径别名:

json
{
  "compilerOptions": {
  	"baseUrl": ".",
	"paths": {
	  "@/*": ["./src/*"]
	}
  }
}

并且您的后端代码如下:

typescript
import { Elysia } from 'elysia'
import { a, b } from '@/controllers'

const app = new Elysia()
	.use(a)
	.use(b)
	.listen(3000)

export type app = typeof app

必须 确保您的前端代码能够解析相同的路径别名。否则,类型推断将被解析为 any。

typescript
import { treaty } from '@elysiajs/eden'
import type { app } from '@/index'

const client = treaty<app>('localhost:3000')

// 这应该能够在前端和后端解析相同的模块,而不是 `any`
import { a, b } from '@/controllers'

要修复此问题,您必须确保路径别名在前端和后端解析到相同的文件。

因此,您必须将 tsconfig.json 中的路径别名更改为:

json
{
  "compilerOptions": {
  	"baseUrl": ".",
	"paths": {
	  "@/*": ["../apps/backend/src/*"]
	}
  }
}

如果配置正确,您应该能够在前端和后端解析相同的模块。

typescript
// 这应该能够在前端和后端解析相同的模块,而不是 `any`
import { a, b } from '@/controllers'

命名空间

我们推荐为 monorepo 中的每个模块添加 命名空间 前缀,以避免可能发生的任何混淆和冲突。

json
{
  "compilerOptions": {
  	"baseUrl": ".",
	"paths": {
	  "@frontend/*": ["./apps/frontend/src/*"],
	  "@backend/*": ["./apps/backend/src/*"]
	}
  }
}

然后,您可以像这样导入模块:

typescript
// 应该在前端和后端都能工作,并且不返回 `any`
import { a, b } from '@backend/controllers'

我们推荐创建一个 单一的 tsconfig.json,它将 baseUrl 定义为您的 repo 根目录,根据模块位置提供路径,并为每个模块创建一个 tsconfig.json,它继承根 tsconfig.json,其中包含路径别名。

您可以在此 路径别名示例 repoKozeki Template 中找到一个工作示例。