发布于 2026-01-05 4 阅读
0

TypeGraphQL 1.0 正式发布🚀 由 Mux 主办的 TypeGraphQL DEV 全球展示挑战赛:展示你的项目!

TypeGraphQL 1.0 正式发布🚀

TypeGraphQL

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

终于来了!在最初发布两年多之后,TypeGraphQL 的首个稳定版本终于准备就绪v1.0.0——🎉

这是一个漫长的旅程,始于 2018 年 1 月 31 日发布v0.1.0,其中包含 650 多次提交、85 多次合并 PR 和4.9k 多次 GitHub 星标

如果您还没听说过TypeGraphQL,它是一个现代化的框架,允许您使用 Node.js 中的 TypeScript 仅通过类和装饰器创建 GraphQL API。
要了解为什么“GraphQL + TypeScript = TypeGraphQL” ,请在继续阅读本文之前先查看其初始公告文章。

本文主要介绍最新稳定版本中的新功能和变更。那么,事不宜迟……让我们来看看 TypeGraphQL 1.0 为我们带来了哪些新内容!

表现

性能是开发者经常忽略但又至关重要的因素之一。1.0 版本的主要改进方向之一就是使其速度飞快⚡

TypeGraphQL 本质上是一个构建在 JavaScript 参考 GraphQL 实现之上的抽象层graphql-js。为了衡量该抽象层的开销,我们制作了一些演示示例,并将其与使用原始库的“裸机”进行比较graphql-js

结果表明,在最苛刻的情况下,例如返回包含 25000 个嵌套对象的数组,旧版本的0.17速度甚至慢了大约 5 倍!

图书馆 执行时间
TypeGraphQLv0.17 1253.28 毫秒
graphql-js 265.52毫秒

在对代码进行性能分析并找到所有根本原因(例如始终使用异步执行路径)后,开销从 500% 降低到17%v1.0.0!通过使用simpleResolvers它,开销还可以进一步降低,最高可达 13%:

执行时间
graphql-js 265.52毫秒
TypeGraphQLv1.0 310.36毫秒
使用“simpleResolvers” 299.61毫秒
使用全局中间件 1267.82 毫秒

如此小的开销比最初的 500% 更容易接受!
有关如何在更复杂的情况下启用性能优化的更多信息,请参阅文档📖

模式隔离

这是另一个乍看之下并不明显的特性,但它提供了新的可能性,例如将模式拆分为公共模式和私有模式👀

在 0.17.x 及更早版本中,模式是根据评估 TypeGraphQL 装饰器收集的所有元数据构建的。这种方法的缺点是模式泄漏——每次后续调用buildSchema都会返回相同的模式,该模式是由元数据存储中找到的所有类型和解析器组合而成的。

在 TypeGraphQL 1.0 中,情况已不再如此!
现在模式是隔离的,这意味着调用会从选项数组中buildSchema获取数据resolvers,并且只会发出与这些解析器相关的查询、变更和类型。

const firstSchema = await buildSchema({
  resolvers: [FirstResolver],
});
const secondSchema = await buildSchema({
  resolvers: [SecondResolver],
});
Enter fullscreen mode Exit fullscreen mode

因此,只需修改resolvers选项,我们就可以在 GraphQL schema 中公开不同的操作集!
适当的隔离还能简化无服务器开发,因为它能够消除“Schema 必须包含唯一命名的类型”等错误。

指令和扩展

这两个新功能是两种互补的方式,可以用来添加有关模式项的元数据。

GraphQL 指令虽然语法可能让人联想到 TypeScript 装饰器(指令是一个以 @ 字符开头的标识符),但实际上,它们是纯粹的模式定义语言 (Schema Definition Language) 特性。除了元数据功能外,它们还可以修改模式,例如生成用于分页的连接类型。基本上,它们看起来像这样:

type Query {
  foobar: String! @auth(requires: USER) 
}
Enter fullscreen mode Exit fullscreen mode

要应用它们,我们只需要@Directive在上面添加装饰器并提供字符串参数,例如:

@Resolver()
class FooBarResolver {
  @Directive("@auth(requires: USER)")
  @Query()
  foobar(): string {
    return "foobar";
  }
}
Enter fullscreen mode Exit fullscreen mode

然而,另一方面,GraphQL 扩展则是用 JavaScript 实现相同目标的一种方式。在应用一些自定义逻辑时,推荐使用 GraphQL 扩展来放置类型元数据。

要声明类型或选定字段的扩展,我们需要使用@Extensions装饰器,例如:

@ObjectType()
class Foo {
  @Extensions({ roles: [Role.User] })
  @Field()
  bar: string;
}
Enter fullscreen mode Exit fullscreen mode

然后,我们可以通过遍历对象,在解析器或中间件中读取该元数据GraphQLResolveInfo,例如:

export const ExtensionsMiddleware: MiddlewareFn = async ({ info }, next) => {
  const { extensions } = info.parentType.getFields()[info.fieldName];
  console.log(extensions?.roles); // log the metadata
  return next();
};
Enter fullscreen mode Exit fullscreen mode

有关指令扩展功能的更多信息,请参阅文档📖

接口字段的解析器和参数

阻止 TypeGraphQL 完全符合 GraphQL 标准,从而阻碍 1.0 版本发布的最后一个问题是——提供接口字段解析器实现并声明其参数的能力。

基本上,我们可以使用与定义其他字段时相同的语法来定义接口字段的解析器@ObjectType,例如:

@InterfaceType()
abstract class IPerson {
  @Field()
  avatar(@Arg("size") size: number): string {
    return `http://i.pravatar.cc/${size}`;
  }
}
Enter fullscreen mode Exit fullscreen mode

……只有少数例外情况,例如抽象方法和继承,您可以在文档中阅读相关内容

更详细的错误信息

对于新手来说,最令人恼火的问题之一是过于简略的错误信息,没有提供足够的信息来轻松找到代码中的错误。

诸如“无法确定用户的 GraphQL 输入类型”或通用的“生成模式错误”之类的消息,在查找缺陷所在位置时显然不够有帮助。

现在,当出现错误时,系统会给出大致的解释,说明错误发生的原因以及我们可以采取哪些措施来修复它,例如:

Unable to infer GraphQL type from TypeScript reflection system.
  You need to provide explicit type for argument named 'filter'
  of 'getUsers' of 'UserResolver' class.
Enter fullscreen mode Exit fullscreen mode

或者:

Some errors occurred while generating GraphQL schema:
  Interface field 'IUser.accountBalance' expects type 'String!'
  but 'Student.accountBalance' is of type 'Float'
Enter fullscreen mode Exit fullscreen mode

这应该能让开发者节省大量时间,并真正加快开发速度🏎

转换嵌套输入和数组

在之前的版本中,输入类型类的实例仅在第一层输入嵌套中创建。
因此,在类似这样的情况下:

@InputType()
class SampleInput {
  @Field()
  sampleStringField: string;

  @Field()
  nestedField: SomeNestedInput;
}

@Resolver()
class SampleResolver {
  @Query()
  sampleQuery(@Arg("input") input: SampleInput): boolean {
    return input.nestedField instanceof SomeNestedInput;
  }
}
Enter fullscreen mode Exit fullscreen mode

nestedField属性input只是一个普通的 `T` Object,而不是该类的实例SomeNestedInput。这种行为导致了一些不必要的问题,包括对输入和参数验证的支持有限。

自 1.0 版本发布以来,这个问题已得到解决,所有嵌套的参数和输入都会被正确转换为相应的输入类型类实例,甚至包括深度嵌套的数组 💪

还有一件事……

1.0 版本发布并非我们的最终版本!我们收到了来自社区的大量功能请求,也有很多想法正在酝酿之中,敬请期待更多精彩内容!💪

另外,请记住 TypeGraphQL 是一个采用 MIT 许可证的开源项目。它背后没有大型公司支持——它的持续开发完全依赖于社区的支持。

GitHub赞助商

开放集体

如果您喜欢 TypeGraphQL,请考虑支持我们的工作并帮助其发展,特别是如果您将其用于商业用途——这只是为了确保您的产品所依赖的项目得到积极维护和改进。

GitHub 标志 MichalLytek / type-graphql

使用 TypeScript、类和装饰器创建 GraphQL schema 和解析器!

标识

TypeGraphQL

发布 网站 codeql Discord 代码发现 npm 开放集体

使用TypeScript 、类和装饰器创建GraphQL schema 和解析器

https://typegraphql.com

捐

介绍

TypeGraphQL让开发 GraphQL API 成为一个愉快的过程,即仅使用类和一些装饰器魔法来定义模式。

因此,要创建对象类型或输入类型之类的类型,我们使用一种 DTO 类。例如,要声明Recipe类型,我们只需创建一个类并使用装饰器对其进行注解:

@ObjectType()
class Recipe {
  @Field(type => ID)
  id: string;

  @Field()
  title: string;

  @Field(type => [Rate])
  ratings: Rate[];

  @Field({ nullable: true })
  averageRating?: number;
}
Enter fullscreen mode Exit fullscreen mode

然后我们得到 SDL 中对应的模式部分:

type Recipe {
  id: ID!
  title: String!
  ratings: [
Enter fullscreen mode Exit fullscreen mode
文章来源:https://dev.to/michallytek/announcing-typegraphql-1-0-1d7h