- 重构项目结构:controllers/services -> modules模块化组织 - 新增Drizzle ORM集成和数据库schema定义 - 添加完整的开发规范文档(.cursor/rules/) - 重新组织插件结构为子目录方式 - 新增用户模块和示例代码 - 更新类型定义并移除试验性代码 - 添加API文档和JWT使用示例 关联任务计划文档
4.4 KiB
4.4 KiB
API Schema 类型使用指南
1. Schema 转 TypeScript 类型
在 .schema.ts
文件中定义并导出类型:
// example.schema.ts
import { t, type Static } from 'elysia';
// Schema 定义
export const GetUserByUsernameSchema = t.Object({
username: t.String({
minLength: 2,
maxLength: 50,
description: '用户名',
}),
});
// 从 Schema 推断类型
export type GetUserByUsernameParams = Static<typeof GetUserByUsernameSchema>;
2. 在 Service 中使用类型
// example.service.ts
import type { GetUserByUsernameParams, UserInfo } from './example.schema';
export class ExampleService {
// 使用类型注解参数
async getUserByUsername(params: GetUserByUsernameParams): Promise<UserInfo> {
const { username } = params; // TypeScript 会自动推断类型
// 业务逻辑...
return userResult;
}
// 或者直接使用解构参数
async getUserByUsername2({ username }: GetUserByUsernameParams): Promise<UserInfo> {
// 业务逻辑...
return userResult;
}
}
3. 在 Controller 中使用类型
// example.controller.ts
import type { GetUserByUsernameParams, UserInfo } from './example.schema';
import { GetUserByUsernameSchema } from './example.schema';
export const controller = new Elysia()
.get(
'/user/:username',
async ({ params }) => {
// params 自动推断为 GetUserByUsernameParams 类型
const userInfo: UserInfo = await service.getUserByUsername(params);
return successResponse(userInfo);
},
{
// 使用 Schema 进行运行时验证
params: GetUserByUsernameSchema,
}
);
4. 在测试中使用类型
// example.test.ts
import type { GetUserByUsernameParams, UserInfo } from './example.schema';
describe('用户查询测试', () => {
it('应该正确处理参数类型', () => {
// 类型安全的测试数据
const validParams: GetUserByUsernameParams = {
username: 'testuser'
};
const invalidParams = {
username: 'a' // TypeScript 会提示这可能不符合验证规则
};
});
});
5. 工具函数中使用类型
// utils/validators.ts
import type { GetUserByUsernameParams } from '../modules/sample/example.schema';
// 类型安全的验证函数
export function validateUsername(params: GetUserByUsernameParams): boolean {
return params.username.length >= 2 && params.username.length <= 50;
}
// 类型安全的格式化函数
export function formatUserQuery(params: GetUserByUsernameParams): string {
return `查询用户: ${params.username}`;
}
6. 响应类型使用示例
// example.response.ts
import { t, type Static } from 'elysia';
import { UserInfoSchema } from './example.schema';
export const GetUserSuccessResponse = t.Object({
code: t.Literal(0),
message: t.String(),
data: UserInfoSchema,
});
// 导出响应类型
export type GetUserSuccessResponseType = Static<typeof GetUserSuccessResponse>;
7. 完整的类型流转示例
// 完整的类型安全流程
import type {
GetUserByUsernameParams,
UserInfo
} from './example.schema';
// Service 层
class UserService {
async getUser(params: GetUserByUsernameParams): Promise<UserInfo> {
// params.username 有完整的类型提示
// 返回值必须符合 UserInfo 类型
}
}
// Controller 层
const controller = new Elysia()
.get('/user/:username', async ({ params }) => {
// params 自动推断类型
const user = await userService.getUser(params);
// user 自动推断为 UserInfo 类型
return { code: 0, message: '成功', data: user };
}, {
params: GetUserByUsernameSchema, // 运行时验证
});
💡 最佳实践
- 总是导出类型:每个 Schema 都应该导出对应的 TypeScript 类型
- 类型注解:在 Service 方法中明确使用类型注解
- 一致命名:类型名应该与 Schema 名保持一致的命名规范
- 分离关注点:Schema 用于运行时验证,Type 用于编译时类型检查