Skip to content

类型

这是在 Vafast 中编写验证类型的常见模式。

基本类型

TypeBox API 是围绕 TypeScript 类型设计的,并与之类似。

有许多熟悉的名称和行为与 TypeScript 对应项交叉,例如 StringNumberBooleanObject,以及更高级的功能,如 IntersectKeyOfTuple,以增强灵活性。

如果你熟悉 TypeScript,创建 TypeBox 模式的行为就像编写 TypeScript 类型一样,只是它在运行时提供实际的类型验证。

要创建第一个模式,从 TypeBox 导入 Type,并从最基本的类型开始:

typescript
import { Server, defineRoute, defineRoutes, Type } from 'vafast'

const BodySchema = Type.String()

const routes = defineRoutes([
  defineRoute({
    method: 'POST',
    path: '/',
    // schema 会自动验证并返回 400 错误
    schema: { body: BodySchema },
    handler: ({ body }) => `Hello ${body}`
  })
])

const server = new Server(routes)
export default { fetch: server.fetch }

这段代码告诉 Vafast 验证传入的 HTTP 主体,确保主体是一个字符串。如果它是字符串,则可以在请求管道和处理程序中流动。

如果形状不匹配,将抛出验证错误。

基本类型

TypeBox 提供具有与 TypeScript 类型相同行为的基本原始类型。

以下表格列出了最常见的基本类型:

TypeBoxTypeScript
typescript
Type.String()
typescript
string
typescript
Type.Number()
typescript
number
typescript
Type.Boolean()
typescript
boolean
typescript
Type.Null()
typescript
null
typescript
Type.Undefined()
typescript
undefined
typescript
Type.Any()
typescript
any
typescript
Type.Unknown()
typescript
unknown
typescript
Type.Never()
typescript
never
typescript
Type.Void()
typescript
void
typescript
Type.Symbol()
typescript
symbol
typescript
Type.BigInt()
typescript
bigint

字符串类型

TypeBox 提供了多种字符串验证选项:

typescript
import { Type } from 'vafast'

// 基本字符串
const basicString = Type.String()

// 带长度限制的字符串
const limitedString = Type.String({ 
  minLength: 1, 
  maxLength: 100 
})

// 带正则表达式的字符串
const emailString = Type.String({ 
  format: 'email' 
})

// 带枚举值的字符串
const statusString = Type.Union([
  Type.Literal('active'),
  Type.Literal('inactive'),
  Type.Literal('pending')
])

数字类型

typescript
import { Type } from 'vafast'

// 基本数字
const basicNumber = Type.Number()

// 带范围限制的数字
const ageNumber = Type.Number({ 
  minimum: 0, 
  maximum: 150 
})

// 整数
const integerNumber = Type.Integer()

// 正数
const positiveNumber = Type.Number({ 
  minimum: 0, 
  exclusiveMinimum: true 
})

对象类型

typescript
import { Type } from 'vafast'

// 基本对象
const userObject = Type.Object({
  id: Type.Number(),
  name: Type.String(),
  email: Type.String({ format: 'email' }),
  age: Type.Optional(Type.Number())
})

// 嵌套对象
const addressObject = Type.Object({
  street: Type.String(),
  city: Type.String(),
  country: Type.String()
})

const userWithAddress = Type.Object({
  ...userObject.properties,
  address: addressObject
})

数组类型

typescript
import { Type } from 'vafast'

// 基本数组
const stringArray = Type.Array(Type.String())

// 带长度限制的数组
const limitedArray = Type.Array(Type.Number(), {
  minItems: 1,
  maxItems: 10
})

// 元组类型
const tuple = Type.Tuple([
  Type.String(),
  Type.Number(),
  Type.Boolean()
])

Vafast 类型

Vafast 使用 TypeBox 进行类型验证,提供了完整的类型安全。

请求体验证

typescript
import { Server, defineRoute, defineRoutes, Type } from 'vafast'

const userSchema = Type.Object({
  name: Type.String({ minLength: 1 }),
  email: Type.String({ format: 'email' }),
  age: Type.Optional(Type.Number({ minimum: 0 }))
})

const routes = defineRoutes([
  defineRoute({
    method: 'POST',
    path: '/users',
    // schema 自动验证 body,验证失败返回 400
    schema: { body: userSchema },
    handler: ({ body }) => ({ success: true, data: body })
  })
])

const server = new Server(routes)
export default { fetch: server.fetch }

查询参数验证

typescript
import { Server, defineRoute, defineRoutes, Type } from 'vafast'

const querySchema = Type.Object({
  page: Type.Optional(Type.Number({ minimum: 1 })),
  limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100 })),
  search: Type.Optional(Type.String())
})

const routes = defineRoutes([
  defineRoute({
    method: 'GET',
    path: '/users',
    // schema 自动解析和验证 query 参数
    schema: { query: querySchema },
    handler: ({ query }) => ({
      page: query.page ?? 1,
      limit: query.limit ?? 10,
      search: query.search ?? ''
    })
  })
])

const server = new Server(routes)
export default { fetch: server.fetch }

路径参数验证

typescript
import { Server, defineRoute, defineRoutes, Type } from 'vafast'

const paramsSchema = Type.Object({
  id: Type.String({ minLength: 1 })
})

const routes = defineRoutes([
  defineRoute({
    method: 'GET',
    path: '/users/:id',
    // schema 自动验证 params
    schema: { params: paramsSchema },
    handler: ({ params }) => ({ userId: params.id })
  })
])

const server = new Server(routes)
export default { fetch: server.fetch }

头部验证

typescript
import { Server, defineRoute, defineRoutes, Type } from 'vafast'

const headersSchema = Type.Object({
  authorization: Type.String({ pattern: '^Bearer .+' })
})

const routes = defineRoutes([
  defineRoute({
    method: 'POST',
    path: '/secure',
    // schema 自动验证 headers
    schema: { headers: headersSchema },
    handler: ({ headers }) => {
      const token = headers.authorization.replace('Bearer ', '')
      return { token }
    }
  })
])

const server = new Server(routes)
export default { fetch: server.fetch }

Vafast 行为

Vafast 与 TypeBox 的集成提供了以下特性:

自动类型推断

typescript
import { Type, type Static } from 'vafast'

// 定义模式
const userSchema = Type.Object({
  name: Type.String(),
  email: Type.String({ format: 'email' }),
  age: Type.Number({ minimum: 0 })
})

// TypeScript 自动推断类型
type User = Static<typeof userSchema>
// 等同于: { name: string; email: string; age: number }

验证错误处理

使用 defineRoute 时,验证错误会自动返回 400 响应。如果需要自定义错误处理:

typescript
import { Server, defineRoute, defineRoutes, Type } from 'vafast'

const userSchema = Type.Object({
  name: Type.String({ minLength: 1 }),
  email: Type.String({ format: 'email' })
})

const routes = defineRoutes([
  defineRoute({
    method: 'POST',
    path: '/users',
    // 基本用法:验证失败自动返回 400
    schema: { body: userSchema },
    handler: ({ body }) => ({ success: true, data: body })
  })
])

const server = new Server(routes)
export default { fetch: server.fetch }

如果需要获取详细的验证错误信息,可以使用自定义错误处理中间件:

typescript
import { Type } from 'vafast'
import { TypeCompiler } from '@sinclair/typebox/compiler'

// 自定义验证错误处理(高级用法)
const userValidator = TypeCompiler.Compile(userSchema)

const validateWithDetails = (data: unknown) => {
  const errors = [...userValidator.Errors(data)]
  if (errors.length > 0) {
    return {
      valid: false,
      errors: errors.map(e => ({
        path: e.path,
        message: e.message
      }))
    }
  }
  return { valid: true, errors: [] }
}

高级类型模式

联合类型

typescript
const statusSchema = Type.Union([
  Type.Literal('active'),
  Type.Literal('inactive'),
  Type.Literal('pending')
])

const userStatusSchema = Type.Object({
  id: Type.Number(),
  status: statusSchema,
  updatedAt: Type.String({ format: 'date-time' })
})

交叉类型

typescript
const baseUserSchema = Type.Object({
  name: Type.String(),
  email: Type.String({ format: 'email' })
})

const adminUserSchema = Type.Object({
  role: Type.Literal('admin'),
  permissions: Type.Array(Type.String())
})

const adminUser = Type.Intersect([baseUserSchema, adminUserSchema])

递归类型

typescript
import { Type } from 'vafast'

const commentSchema = Type.Recursive(This => Type.Object({
  id: Type.Number(),
  content: Type.String(),
  author: Type.String(),
  replies: Type.Array(This)
}))

性能优化

预编译验证器

推荐

defineRoute 内部已自动预编译 Schema,通常无需手动预编译。以下仅用于了解底层原理或脱离 Vafast 单独使用 TypeBox。

typescript
import { TypeCompiler } from '@sinclair/typebox/compiler'
import { Type } from 'vafast'

const userSchema = Type.Object({
  name: Type.String(),
  email: Type.String()
})

// 手动预编译(defineRoute 已内置,通常不需要)
const userValidator = TypeCompiler.Compile(userSchema)

// 使用预编译的验证器
const isValid = userValidator.Check({ name: 'John', email: 'john@example.com' })

最佳实践

1. 使用描述性的错误消息

typescript
const userSchema = Type.Object({
  name: Type.String({
    minLength: 1,
    error: 'Name is required'
  }),
  email: Type.String({
    format: 'email',
    error: 'Please provide a valid email address'
  }),
  age: Type.Number({
    minimum: 0,
    maximum: 150,
    error: 'Age must be between 0 and 150'
  })
})

2. 重用验证模式

typescript
import { Type } from 'vafast'

// 基础模式
const baseUserSchema = Type.Object({
  name: Type.String({ minLength: 1 }),
  email: Type.String({ format: 'email' })
})

// 创建用户模式
const createUserSchema = baseUserSchema

// 更新用户模式
const updateUserSchema = Type.Partial(baseUserSchema)

// 用户列表查询模式
const userQuerySchema = Type.Object({
  page: Type.Optional(Type.Number({ minimum: 1 })),
  limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100 })),
  search: Type.Optional(Type.String())
})

3. 类型安全的路由定义

typescript
import { Server, defineRoute, defineRoutes, Type } from 'vafast'
import type { Static } from 'vafast'

// 定义模式
const userSchema = Type.Object({
  name: Type.String({ minLength: 1 }),
  email: Type.String({ format: 'email' })
})

type User = Static<typeof userSchema>

const paramsSchema = Type.Object({
  id: Type.String()
})

// 定义路由 - 使用 defineRoute 自动获得类型安全
const routes = defineRoutes([
  defineRoute({
    method: 'GET',
    path: '/users/:id',
    schema: { params: paramsSchema },
    handler: ({ params }) => ({ userId: params.id })
  }),
  defineRoute({
    method: 'POST',
    path: '/users',
    schema: { body: userSchema },
    // body 已经是完全类型安全的 User 类型
    handler: ({ body }) => ({ success: true, user: body })
  })
])

const server = new Server(routes)
export default { fetch: server.fetch }

总结

Vafast 的类型系统提供了:

  • ✅ 基于 TypeBox 的完整类型安全
  • ✅ 运行时数据验证
  • ✅ 自动类型推断
  • ✅ 灵活的验证规则
  • ✅ 性能优化选项
  • ✅ 错误处理支持

下一步

如果您有任何问题,请查看我们的 社区页面GitHub 仓库