新闻详情

新闻详情

首页 / 资讯中心 / 详情

TypeGraphQL 类型与字段:用类与装饰器声明 GraphQL Object Type

发布时间:2026/9/27 8:48:23来源:尧图网络
TypeGraphQL 类型与字段:用类与装饰器声明 GraphQL Object Type
后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载TypeGraphQL 的核心思路是从 TypeScript 类自动生成 GraphQL schema 定义无需手写 SDL 文件或重复描述 schema 的接口。本篇指南以 Recipe 模型为例完整讲解ObjectType与Field装饰器的用法如何声明字段、显式标注数组与泛型类型、精确控制列表及嵌套列表的 nullability、为字段添加描述与弃用标记以及如何在 schema 中重命名类型与字段。读完本文你将能独立用 TypeGraphQL 定义出严谨、可读、与graphql-js语义完全一致的对象类型。从 TypeScript 类到 GraphQL 类型核心思想TypeGraphQL 的设计目标非常明确以类与装饰器为唯一的事实来源自动生成 GraphQL schema 定义。这避免了传统方案中SDL 文件 接口/类型 解析器三处重复维护的痛点仅凭装饰器和一点点 TypeScript 反射reflection机制即可完成 schema 生成。先从一个普通的 TypeScript 类开始。它代表我们的Recipe数据模型包含存储食谱数据的字段class Recipe { id: string; title: string; ratings: Rate[]; averageRating?: number; }此时它只是一个普通类GraphQL 并不知道它的存在。要让 TypeGraphQL 把它当作 GraphQL 的type即 SDL 中的type关键字或graphql-js中的GraphQLObjectType第一步是给类加上ObjectType()装饰器ObjectType() class Recipe { id: string; title: string; ratings: Rate[]; averageRating: number; }ObjectType装饰器内部会把类的元数据收集到 TypeGraphQL 的 metadata storage 中——从 ObjectType.ts 源码可以看到它调用了getMetadataStorage().collectObjectMetadata(...)并注册name默认取target.name、description、implements接口实现等信息。不过仅仅标记类还不够。类里的哪些属性要暴露为 GraphQL 字段需要逐个声明——这正是Field装饰器的职责。用 Field 声明属性并收集反射元数据Field装饰器做两件事声明类属性映射为 GraphQL 字段同时从 TypeScript 反射系统收集该属性的类型元数据。我们给Recipe的每个公开属性都加上Field()ObjectType() class Recipe { Field() id: string; Field() title: string; Field() ratings: Rate[]; Field() averageRating: number; }从 Field.ts 源码可以看到Field的完整执行流程拒绝 symbol 类型的属性键抛出SymbolKeysNotSupportedError解析重载参数可能传入类型函数、options 对象或两者都不传调用 findType.ts 读取反射元数据design:type或design:returntype配合显式传入的类型函数确定最终 GraphQL 类型调用collectClassFieldMetadata注册字段元数据包括schemaName即 options.name 或属性名、getType、typeOptions、complexity、description、deprecationReason等。对于string、boolean、number这类简单类型Field()什么都不传就够了——反射系统能直接读出正确类型。真正需要显式标注的是泛型类型。数组类型必须显式声明type [T]由于 TypeScript 反射系统的限制装饰器只能拿到属性声明处的构造器如Array拿不到泛型参数如Rate。所以声明Rate[]时必须用Field(type [Rate])的显式数组语法告诉编译器Field(type [Rate]) ratings: Rate[];嵌套数组同样用[ ]符号逐层标注深度。例如Field(type [[Int]])表示期望一个深度为 2 的整数数组。为什么这里采用函数语法而不是{ type: Rate }这样的配置对象因为函数thunk语法能规避循环依赖问题例如Post -- User相互引用时模块加载顺序导致的undefined引用。这也是社区普遍接受这一约定convention的原因。如果你想少敲几个键可以写成简写Field(() Rate)但可读性略差需要读者自行权衡。从实现层面看findType.ts 中的findTypeValueArrayDepth函数会递归展开returnTypeFunc()的返回值解析出数组深度arrayDepth与最内层元素类型供 schema 生成阶段构造GraphQLList。在 types.ts 中ReturnTypeFunc被定义为(returns?: void) TypeValue | RecursiveArrayTypeValueRecursiveArray正是允许任意嵌套数组字面量的类型来源。覆盖反射推断type ID / Int / 自定义标量Field的类型函数同样可以覆盖反射推断出的类型。例如Recipe.id属性在 TypeScript 中是string但 GraphQL 语义上我们希望它是ID标量Field(type ID) id: string;Rate.value是number但我们希望映射为整数标量IntField(type Int) value: number;ID、Int是 TypeGraphQL 提供的三个基础标量别名Int→GraphQLInt、Float→GraphQLFloat、ID→GraphQLID用于省去引入graphql包的键盘开销。注意 JavaScript 的Number类型默认会映射为GraphQLFloat见 helpers/types.ts 中convertTypeIfScalar的case Number: return GraphQLFloat因此number属性想映射成Int时必须显式传type Int。关于这些标量的完整说明包括内置的Date标量与自定义标量注册参见 scalars.md。隐藏字段不写 Field 的属性不进 schemaRate类中还有一个微妙的细节——user属性没有Field()装饰器ObjectType() class Rate { Field(type Int) value: number; Field() date: Date; user: User; // 没有 Field不暴露到 schema }这正是一种数据隐藏手段user字段需要持久化到数据库例如用于防止同一用户重复评分但你不希望它通过 GraphQL 公之于众。只对类中需要公开的属性加Field()即可。上面Rate类生成的 SDL 等价物如下——user没有出现在其中type Rate { value: Int! date: Date! }nullability默认非空按需放宽TypeGraphQL 的默认行为与 TypeScript 属性语义保持一致所有字段默认非空non-null。也就是Field()默认生成String!、Int!这样的类型。单值字段的 nullable: true当属性可能没有值比如averageRating在食谱还没有评分时是未定义的我们需要两处配合在 TypeScript 侧用?:把属性声明为可选在Field配置中传入{ nullable: true }。Field({ nullable: true }) averageRating?: number;⚠️ 特别注意当你把类型声明为可空联合如string | null时必须显式给Field提供类型函数——因为 TypeScript 对联合类型的反射结果通常是Object无法自动推断出正确的 GraphQL 类型。这一点在 scalars.md 的示例中也有印证get optionalInfo(): string | undefined时需要显式Field(type String, { nullable: true })。列表字段的精细化空值控制列表类型的 nullability 比单值更复杂因为列表整体和列表元素的空值语义是相互独立的。{ nullable: true | false }这种基础配置只作用于列表整体对应 SDL 中的[Item!]列表可空或[Item!]!列表非空。如果需要一个稀疏数组元素允许为 null则要使用两个特殊取值nullable 取值生成 SDL语义false默认[Item!]!列表非空、元素非空true[Item!]列表可空、元素非空items[Item]!列表非空、元素可空itemsAndList[Item]列表可空、元素也可空注意nullableByDefault: true在buildSchema配置中开启见 bootstrap.md同样会作用于列表把默认的[Item!]!变成[Item]——效果等同于nullable: itemsAndList。嵌套列表的空值传播规则对于嵌套列表nullable选项会作用于整个数组深度。以Field(() [[Item]])为例默认情况生成[[Item!]!]!每一层都非空nullable: itemsAndList生成[[Item]]每一层都可空nullable: items生成[[Item]]!最外层非空内层可空。这些规则在源码层面有精确对应。helpers/types.ts 的wrapWithTypeOptions函数是整个空值包装逻辑的核心它根据typeOptions.nullable与nullableByDefault判断每一层是否用GraphQLNonNull包裹wrapTypeInNestedList则递归按arrayDepth构造嵌套的GraphQLList。同时把items/itemsAndList用在非数组字段上会直接抛出WrongNullableListOptionError见 errors/index.ts因此这两个选项只适用于列表字段。测试用例也对上述空值规则做了完整覆盖在 tests/functional/fields.ts 中arrayWithNullableItemFieldnullable: itemsAndList验证生成列表可空、元素可空的结构nonNullArrayWithNullableItemFieldnullable: items验证列表非空、元素可空而nonNullNestedArrayWithNullableItemField与nestedArrayWithNullableItemField则分别验证嵌套数组在items与itemsAndList下的逐层类型结构。description 与 deprecationReason让 schema 自文档化在Field的配置对象中还可以提供面向 GraphQL schema 用途的元信息description字段描述会写入 schema 并出现在 GraphQL introspection 与文档工具中deprecationReason字段弃用原因标注后客户端工具会在 schema 中把该字段标记为deprecated。ObjectType同样支持descriptionObjectTypeOptions类型中description与implements等选项的定义见 ObjectType.ts。字段元数据在 field-metadata.ts 中对应description与deprecationReason两个属性均来自Field的 options。完整示例与生成的 SDL把前面所有特性组合起来Recipe类最终长这样ObjectType({ description: The recipe model }) class Recipe { Field(type ID) id: string; Field({ description: The title of the recipe }) title: string; Field(type [Rate]) ratings: Rate[]; Field({ nullable: true }) averageRating?: number; }这段声明生成的 GraphQL schema 片段SDL为type Recipe { id: ID! title: String! ratings: [Rate!]! averageRating: Float }对照可见三条关键映射stringtype ID→ID!string description →String!描述随 introspection 可见Rate[]type [Rate]→[Rate!]!number{ nullable: true }→Float可空。计算型字段与 field resolver如果对象类型的某个字段纯粹由其他字段计算而来例如averageRating由ratings数组算得而且你不想污染类的签名可以完全省略该属性转而通过 field resolver 实现。field resolver 的详细做法FieldResolver()Root()注入父对象、ResolverInterfaceT增强类型安全等参见 resolvers.md其中也包含averageRating的完整实现示例。注意事项与边界禁止定义构造函数在对象类型类中定义构造函数是严格禁止的——TypeGraphQL 在底层会自行创建对象类型类的实例相关机制可参考 helpers/types.ts 中convertToType函数它通过new (Target as any)()来实例化输入数据对应的类型。自定义构造函数会破坏这一实例化流程。用 name 重命名类型与字段某些场景下我们希望内部类名/属性名与对外暴露的 schema 名称不同。ObjectType与Field都支持nameObjectType(ExternalTypeName) class InternalClassName { Field({ name: externalFieldName }) internalPropertyName: string; }在 ObjectType.ts 中getNameDecoratorParams会解析第一个字符串参数作为name最终注册的name: name || target.name在 Field.ts 中schemaName取options.name || propertyKey且 metadata storage 同时保存name内部属性名与schemaName对外 schema 名。⚠️ 但需注意字段重命名只对输出类型object type、interface type有效对输入类型input type无效。原因在于输入字段没有 resolver 可以把一个字段值翻译成另一个属性值——重命名后没有翻译层来还原数据因此 TypeGraphQL 不支持在输入侧做字段改名。小结主题关键点仓库依据ObjectType把类标记为 GraphQL object type支持name/description/implementssrc/decorators/ObjectType.tsField声明属性为 GraphQL 字段收集反射元数据支持nullable/description/deprecationReason/name/complexitysrc/decorators/Field.ts数组与嵌套数组必须显式type [T]/[[T]]函数语法解决循环依赖src/helpers/findType.ts标量覆盖type ID、type Int覆盖反射推断docs/scalars.md列表空值nullable: items/itemsAndList精细化控制元素与整体src/helpers/types.ts、tests/functional/fields.ts全局默认空值buildSchema({ nullableByDefault: true })src/schema/build-context.ts如果想在真实项目里看到这些字段定义方式的综合应用可以直接阅读仓库中的示例代码例如 examples/simple-usage 下的recipe.type.tsRecipe对象类型定义与recipe.input.tsAddRecipeInput输入类型以及 examples/generic-types/paginated-response.type.ts用类工厂模式实现泛型分页类型其中就包含Field(type [TItemClass])的数组类型声明。更进一步泛型类型的完整指南见 generic-types.md接口与继承相关的字段扩展见 interfaces.md 与 inheritance.md。/output文章赞分享后端GraphQLAPI设计【免费下载链接】type-graphqlCreate GraphQL schema and resolvers with TypeScript, using classes and decorators!项目地址https://gitcode.com/gh_mirrors/ty/type-graphql点击查看免费下载相关推荐TypeGraphQL 类型与字段映射全指南用 TypeScript 类与装饰器构建 GraphQL SchemaTypeGraphQL 类型与字段映射全指南用 TypeScript 类与装饰器构建 GraphQL Schema 导读 本指南聚焦 TypeGraphQL后端GraphQLAPI设计RustOwl开发路线图未来版本功能预测与展望RustOwl开发路线图未来版本功能预测与展望 你是否在调试Rust程序时仍为所有权和生命周期问题感到困惑是否希望有更直观的工具帮助理解复杂的内存管理逻辑后端GraphQLAPI设计TypeGraphQL 入门指南用 TypeScript 类与装饰器声明式构建 GraphQL Schema 与 ResolverTypeGraphQL 入门指南用 TypeScript 类与装饰器声明式构建 GraphQL Schema 与 Resolver 导读 TypeGraphQ后端GraphQLAPI设计上一篇AG-UI路由管理终极指南Next.js App Router最佳实践下一篇gorush源码贡献指南从Issue到PR的完整流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

给传销做网站什么罪 2026最新避坑指南 2026/9/27 9:36:18

给传销做网站什么罪 2026最新避坑指南

给传销做网站什么罪 2026最新避坑指南 域名服务器搞不懂?别慌,2026年入行建站,最忌讳的就是“糊涂账”。很多新手刚接第一单,甲方扔过来一个“内部管理系统”,你一看代码逻辑,层级裂变、拉人头奖励、资金池流转……心里直打鼓:这要是给传销做…

阅读更多 →
Puppet file_content 文件内容端点:HTTP API、挂载点原理与 fileserver.conf 配置实战 2026/9/27 9:36:18

Puppet file_content 文件内容端点:HTTP API、挂载点原理与 fileserver.conf 配置实战

运维DevOpsIaC 【免费下载链接】puppet Server automation framework and application 项目地址: https://gitcode.com/gh_mirrors/pu/puppet 点击查看 免费下载 导读 file_content 是 Puppet 服务端(Puppet Server / Puppet master)提供的…

阅读更多 →
佛山百度推广seo服务避坑指南3个实操对比评测 2026/9/27 9:36:18

佛山百度推广seo服务避坑指南3个实操对比评测

佛山百度推广seo服务避坑指南3个实操对比评测 网站被黑挂马,后台突然多出几百条垃圾外链,百度收录直接清零,这种深夜接到客户电话的崩溃时刻,做网站的朋友都经历过。很多老板在佛山找【佛山百度推广seo服务】时,只看报价单上的数字,忽略了服务商…

阅读更多 →
Adobe Illustrator Ai 2025最详细保姆级安装教 2026/9/27 9:36:18

Adobe Illustrator Ai 2025最详细保姆级安装教

【名称】:Adobe Illustrator 2025 【大小】:64位/3.9G 【语言】:中文版 【安装环境】:Win10及以上 【AI 2025 软件链接】: 软件介绍 Adobe illustrator,常被称为“AI”,是一种应用于出版、多媒…

阅读更多 →
Open Pencil Vue SDK 实战:用 useVariablesDialogState 打造自定义变量编辑对话框 2026/9/27 9:36:11

Open Pencil Vue SDK 实战:用 useVariablesDialogState 打造自定义变量编辑对话框

前端桌面应用AI 应用MCP 服务 【免费下载链接】open-pencil AI-native design editor. Open-source Figma alternative. 项目地址: https://gitcode.com/gh_mirrors/op/open-pencil 点击查看 免费下载 useVariablesDialogState() 是 Open Pencil Vue SDK 中面向「变…

阅读更多 →
深圳网络优化培训2026最新:备案不卡壳的实战指南 2026/9/27 9:35:52

深圳网络优化培训2026最新:备案不卡壳的实战指南

深圳网络优化培训2026最新:备案不卡壳的实战指南 刚接触深圳网络优化培训的朋友,是不是对着备案流程一头雾水?明明照着网上旧教程操作,服务器一提交就被打回,改了三遍还是卡在“主体信息不一致”上,心态直接崩了。别慌,这正是2026年最新政策调…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉