cursor-init/docs/api-type-usage-examples.md

4.1 KiB
Raw Blame History

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/example/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, // 运行时验证
    },
);

💡 最佳实践

  1. 总是导出类型:每个 Schema 都应该导出对应的 TypeScript 类型
  2. 类型注解:在 Service 方法中明确使用类型注解
  3. 一致命名:类型名应该与 Schema 名保持一致的命名规范
  4. 分离关注点Schema 用于运行时验证Type 用于编译时类型检查