后端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),仅供参考
企业数字化 ERP 产品动态
相关推荐
featuretools API 参考全指南:从演示数据集到深度特征合成与特征工程的完整接口地图 特征工程机器学习数据科学 【免费下载链接】featuretools An open source python library for automated feature engineering 项目地址: https://gitcode.com/gh_mirrors/fe/featuretools 点击查看 免费下载 本篇指南以 featuretools 官方 API Referenceÿ… · 2026/9/27 8:48:20
jspaint 无障碍化实战:深入解析 Tracky Mouse 头部追踪与驻留点击 API 前端桌面应用图像处理 【免费下载链接】jspaint 🎨 Classic MS Paint, REVIVED ✨Extras 项目地址: https://gitcode.com/gh_mirrors/js/jspaint 点击查看 免费下载 本… · 2026/9/27 8:48:14
3步搞定怎么做网站的学校的大图,兼顾性能优化与防黑 3步搞定怎么做网站的学校的大图,兼顾性能优化与防黑 昨天凌晨两点,我手机突然疯狂震动。老客户张总打来电话,声音都变了调:“你快看看,咱那个学校官网怎么全变了?全是博彩广告,点进去全是挂马链接!家长群都炸了,说我们被黑了!”… · 2026/9/27 9:31:35
第245篇_出入境政策与口岸通关信息采集 【Python爬虫实战】第245篇:政务信息怎么抓——出入境政策与口岸通关信息采集实战 所属专栏:【Python爬虫实战】从零到企业级爬虫工程师(CSDN 付费专栏) 本篇篇目:第 245 篇(政务与公共信息采集专场,每篇都是一个可独立上手的实战项目) 难度等级:中级,需要掌握 reque… · 2026/9/27 9:31:29
网站业务员好做吗?拆解3个最佳实践避坑指南 网站业务员好做吗?拆解3个最佳实践避坑指南 网站做好了没人访问,这大概是做建站销售最头疼的事。很多新人觉得,只要网站做得漂亮,客户就会买单,结果发现根本卖不出去。其实,这背后涉及的是 最佳实践… · 2026/9/27 9:31:11
IDEA按照JSP Model2思想实现用户注册功能 【任务目标】
按照JSP Model2思想编写一个用户注册程序。
组件关系图如下: (1)UserBean: 封装用户信息的JavaBean。 (2)RegisterFormBean是封装注册表单信息的JavaBeanl,用于校验从ControllerServlet中获… · 2026/9/27 9:31:04
CSS 代码格式化在线工具,前端样式调试整理小工具 一、前言
在前端日常开发工作中,我们经常会接触压缩后的 CSS 代码。线上为了减少资源体积,CSS 文件通常会去除换行、空格和缩进,全部合并为单行文本。
当我们需要分析第三方样式、排查样式冲突问题、阅读线上 CSS 源码时,面对挤… · 2026/9/27 9:30:58
使用docker-compose部署项目(mysql、springboot、vue、nginx) 结合前面几篇文章:
9.如何将jar包打包成docker镜像并进行部署 10.docker如何部署一个前端网站
docker系列文章: https://blog.csdn.net/baidu_32523857/article/details/135212681 这篇文章我们使用docker-compose来部署项目。
docker-compose是一个编… · 2026/9/27 9:30:58
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01