Schema 高级操作
farrow-schema 提供了丰富的 Schema 操作工具,让你能够灵活地派生和组合类型。
字段元数据
使用 field 函数添加字段描述:
typescript
import { field } from 'farrow-schema'
class User extends ObjectType {
id = ID
name = field({
__type: String,
description: '用户姓名'
})
email = field({
__type: String,
description: '用户邮箱',
deprecated: '请使用 contactEmail'
})
}Schema 操作工具
pick - 选择字段
typescript
import { pickObject } from 'farrow-schema'
class FullUser extends ObjectType {
id = String
name = String
email = String
password = String
createdAt = Date
}
// 选择公开字段
const PublicUser = pickObject(FullUser, ['id', 'name'])
type PublicUserType = TypeOf<typeof PublicUser>
// { id: string, name: string }omit - 排除字段
typescript
import { omitObject } from 'farrow-schema'
// 排除敏感字段
const SafeUser = omitObject(FullUser, ['password'])
type SafeUserType = TypeOf<typeof SafeUser>
// { id: string, name: string, email: string, createdAt: Date }
// 创建输入类型
const CreateUserInput = omitObject(FullUser, ['id', 'createdAt'])
type CreateUserInputType = TypeOf<typeof CreateUserInput>
// { name: string, email: string, password: string }partial - 转为可选
typescript
import { partialObject } from 'farrow-schema'
class User extends ObjectType {
id = String
name = String
email = String
}
const PartialUser = partialObject(User)
type PartialUserType = TypeOf<typeof PartialUser>
// { id?: string, name?: string, email?: string }
// 实际应用:更新输入
const UpdateUserInput = partialObject(
omitObject(FullUser, ['id', 'createdAt'])
)
// 所有字段都是可选的,用于 PATCH 请求required - 转为必填
typescript
import { requiredObject } from 'farrow-schema'
class OptionalUser extends ObjectType {
id = Optional(String)
name = Optional(String)
}
const RequiredUser = requiredObject(OptionalUser)
type RequiredUserType = TypeOf<typeof RequiredUser>
// { id: string, name: string }keyof - 获取字段键
typescript
import { keyofObject } from 'farrow-schema'
const keys = keyofObject(User)
// ['id', 'name', 'email']💡 提示:所有工具函数都有 Object 和 Struct 专用版本:
pickObject/pickStructomitObject/omitStructpartialObject/partialStructrequiredObject/requiredStructkeyofObject/keyofStruct
推荐使用专用版本以获得更好的类型提示。
交集类型
typescript
import { Intersect } from 'farrow-schema'
class BaseUser extends ObjectType {
id = String
name = String
}
class ContactInfo extends ObjectType {
email = String
phone = String
}
// 合并多个类型
const FullUser = Intersect(BaseUser, ContactInfo)
type FullUserType = TypeOf<typeof FullUser>
// { id: string, name: string, email: string, phone: string }修饰符类型
Strict / NonStrict
在字段级别控制验证模式:
typescript
import { Strict, NonStrict } from 'farrow-schema'
class Product extends ObjectType {
price = Strict(Number) // 必须是纯数字
quantity = NonStrict(Int) // 接受 "42" 并转换为 42
}ReadOnly / ReadOnlyDeep
typescript
import { ReadOnly, ReadOnlyDeep } from 'farrow-schema'
class Config extends ObjectType {
settings = ReadOnly(Record(String)) // 浅层只读
nested = ReadOnlyDeep(ComplexObject) // 深层只读
}元数据提取
基础用法
typescript
import { Formatter } from 'farrow-schema/formatter'
class User extends ObjectType {
id = ID
name = String
age = Number
tags = List(String)
}
const { typeId, types } = Formatter.format(User)
console.log(typeId) // 0 (根类型的 ID)
console.log(types)
/*
{
"0": {
type: "Object",
name: "User",
fields: {
id: { typeId: 1, $ref: "#/types/1" },
name: { typeId: 2, $ref: "#/types/2" },
age: { typeId: 3, $ref: "#/types/3" },
tags: { typeId: 4, $ref: "#/types/4" }
}
},
"1": { type: "Scalar", valueType: "string", valueName: "ID" },
"2": { type: "Scalar", valueType: "string", valueName: "String" },
"3": { type: "Scalar", valueType: "number", valueName: "Number" },
"4": { type: "List", itemTypeId: 2, $ref: "#/types/2" }
}
*/应用场景
生成 API 文档
typescript
import { Formatter, isNamedFormatType } from 'farrow-schema/formatter'
class CreateUserInput extends ObjectType {
name = field({
__type: String,
description: '用户姓名'
})
email = field({
__type: String,
description: '用户邮箱'
})
}
const { typeId, types } = Formatter.format(CreateUserInput)
// 遍历类型生成文档
for (const [id, formatType] of Object.entries(types)) {
if (formatType.type === 'Object') {
console.log(`## ${formatType.name}`)
for (const [fieldName, field] of Object.entries(formatType.fields)) {
console.log(`- **${fieldName}**: ${field.description || ''}`)
}
}
}生成客户端类型
typescript
function generateTypeScript(types: FormatTypes): string {
let code = ''
for (const [id, formatType] of Object.entries(types)) {
if (formatType.type === 'Object') {
code += `export interface ${formatType.name} {\n`
for (const [fieldName, field] of Object.entries(formatType.fields)) {
const fieldType = getTypeScriptType(types[field.typeId])
code += ` ${fieldName}: ${fieldType}\n`
}
code += `}\n\n`
}
}
return code
}组合操作示例
typescript
// 定义完整模型
class FullUser extends ObjectType {
id = String
name = String
email = String
password = String
role = String
createdAt = Date
updatedAt = Date
}
// 派生多个 Schema
const PublicUser = pickObject(FullUser, ['id', 'name'])
const CreateUserInput = omitObject(FullUser, ['id', 'createdAt', 'updatedAt'])
const UpdateUserInput = partialObject(CreateUserInput)
const AdminUser = FullUser // 管理员可以看到完整信息
// 类型推导
type PublicUserType = TypeOf<typeof PublicUser>
// { id: string, name: string }
type CreateUserInputType = TypeOf<typeof CreateUserInput>
// { name: string, email: string, password: string, role: string }
type UpdateUserInputType = TypeOf<typeof UpdateUserInput>
// { name?: string, email?: string, password?: string, role?: string }