[英]Why can't TypeGraphQL determine the type of a generic?
I'm trying to define generic type definitions for building connections and edges in GraphQL.我正在尝试为在 GraphQL 中构建连接和边缘定义通用类型定义。 I'm keeping with the Relay spec, except that I'm also including the conventional nodes
connection property for convenience.我与 Relay 规范保持一致,除了为方便起见我还包括常规nodes
连接属性。 The TypeGraphQL docs show how to do something very similar, but I'm getting the following error when I try to run the server: TypeGraphQL 文档展示了如何做一些非常相似的事情,但是当我尝试运行服务器时出现以下错误:
Cannot determine GraphQL output type for 'nodes' of 'Connection' class.无法确定“连接”class 的“节点”的 GraphQL output 类型。 Is the value, that is used as its TS type or explicit type, decorated with a proper decorator or is it a proper output value?用作其 TS 类型或显式类型的值是用适当的装饰器装饰还是适当的 output 值?
Typically, this shows up when the @ObjectType
decorator is missing from a class definition which is then used as a field type somewhere else;通常,当 class 定义中缺少@ObjectType
装饰器时,就会出现这种情况,然后将其用作其他地方的字段类型; however, I've confirmed that the types I'm passing have definitely been defined with this decorator, and I've also tried with a few different types from my schema.但是,我已经确认我传递的类型肯定是用这个装饰器定义的,而且我也尝试过使用我的模式中的几种不同类型。 The docs demonstrate using a generic as a field definition, so that doesn't seem to be the issue either.文档演示了使用泛型作为字段定义,因此这似乎也不是问题。
My type definitions are as follows:我的类型定义如下:
interface RawEdge<NodeType> {
node: NodeType
}
interface Edge<NodeType> extends RawEdge<NodeType> {
cursor: string
}
function Edge<NodeType>(NodeClass: ClassType<NodeType>) {
@ObjectType({ isAbstract: true })
abstract class Edge {
constructor(identifier: string, node: NodeType) {
this.cursor = Buffer.from(identifier).toString('base64')
this.node = node
}
@Field()
cursor: string
@Field(type => NodeClass)
node: NodeType
}
return Edge
}
interface Connection<NodeType, EdgeType extends Edge<NodeType>> {
totalCount: number
edges: EdgeType[]
nodes: NodeType[]
pageInfo: PageInfo
}
function Connection<NodeType, EdgeType extends Edge<NodeType>>(
NodeClass: ClassType<NodeType>,
EdgeClass: ClassType<Edge<NodeType>>
) {
@ObjectType({ isAbstract: true })
abstract class Connection {
constructor(edges: EdgeType[], page: PageQuery) {
this.totalCount = edges.length
this.edges = edgesToReturn<EdgeType>(edges, page)
this.nodes = this.edges.map(edge => edge.node)
this.pageInfo = pageInfo(this, edges)
}
@Field(type => Int)
totalCount: number
@Field(type => [EdgeClass])
edges: EdgeType[]
@Field(type => [NodeClass])
nodes: NodeType[]
@Field()
pageInfo: PageInfo
}
return Connection
}
EDIT: The following workaround resolves the type issue, which proves that the types being passed in have the proper decorators in their definition.编辑:以下解决方法解决了类型问题,这证明传入的类型在其定义中具有适当的装饰器。 However, this is extremely clunky, so I would like to avoid having to use it if possible.但是,这非常笨重,所以我想尽可能避免使用它。
function Edge<NodeType>(NodeClass: ClassType<NodeType>) {
@ObjectType({ isAbstract: true })
abstract class Edge {
constructor(identifier: string, node: NodeType) {
this.cursor = Buffer.from(identifier).toString('base64')
this.node = node
}
@Field()
cursor: string
// @Field decorator removed
node: NodeType
}
return Edge
}
function Connection<NodeType, EdgeType extends Edge<NodeType>>(
NodeClass: ClassType<NodeType>,
EdgeClass: ClassType<Edge<NodeType>>
) {
@ObjectType({ isAbstract: true })
abstract class Connection {
constructor(edges: EdgeType[], page: PageQuery) {
this.totalCount = edges.length
this.edges = edgesToReturn<EdgeType>(edges, page)
this.nodes = this.edges.map(edge => edge.node)
this.pageInfo = pageInfo(this, edges)
}
@Field(type => Int)
totalCount: number
@Field(type => [EdgeClass])
edges: EdgeType[]
// @Field decorator removed
nodes: NodeType[]
@Field()
pageInfo: PageInfo
}
return Connection
}
type RawDepartmentProductEdge = RawEdge<Product>
@ObjectType()
class DepartmentProductEdge extends Edge(Product) {
// Define the field type here instead of in the generic
@Field(type => Product)
node: Product
}
@ObjectType()
class DepartmentProductConnection extends Connection(Product, DepartmentProductEdge) {
// Define the field type here instead of in the generic
@Field(type => [Product])
nodes: Product[]
}
Context, for anyone who's curious:上下文,对于任何好奇的人:
The purpose of all this is to generate connections using something like this...所有这些的目的是使用这样的东西生成连接......
type RawDepartmentProductEdge = RawEdge<Product>
@ObjectType()
class DepartmentProductEdge extends Edge(Product) {}
@ObjectType()
class DepartmentProductConnection extends Connection(Product, DepartmentProductEdge) {}
...and then populate them like this... ...然后像这样填充它们...
const products = [] // Retrieve the products here
const edges = products.map(node => new DepartmentProductEdge(node.id, node)
const connection = new DepartmentProductConnection(edges, pagination)
...so that everything is as DRY as possible, but I can still add meta to the edges as needed. ...所以一切都尽可能干燥,但我仍然可以根据需要将元添加到边缘。
As it turns out, the code above works just fine: the problem was in sequencing my imports.事实证明,上面的代码工作得很好:问题在于我的导入排序。 I'm using a "bucket" file for exporting all of my GraphQL types, and while that works fine for bringing them into resolvers or middleware, importing from the bucket within type definitions causes weird circular dependency issues.我正在使用“桶”文件来导出我的所有 GraphQL 类型,虽然这可以很好地将它们带入解析器或中间件,但从类型定义中的桶导入会导致奇怪的循环依赖问题。
The solution is just to import types directly from their source files when doing type declarations.解决方案是在进行类型声明时直接从源文件中导入类型。 So, specifically as it applies to the example above:因此,特别适用于上面的示例:
// File system
schema
|- connection
| |- Connection.ts
| |- DepartmentProductConnection.ts
| |- Edge.ts
| |- PageInfo.ts
|- department
| |- Department.ts
|- product
| |- Product.ts
|- index.ts
// index.ts
export * from './connection/Connection'
export * from './connection/Edge'
export * from './connection/PageInfo'
export * from './connection/DepartmentProductConnection'
export * from './department/Department'
export * from './product/Product'
// DepartmentProductConnection.ts
import { ObjectType } from 'type-graphql'
// Don't do this!
// import { Connection, Edge, Product, RawEdge } from '..'
// Instead, do this.
import { Product } from '../product/Product'
import { Connection } from './Connection'
import { Edge, RawEdge } from './Edge'
type RawDepartmentProductEdge = RawEdge<Product>
@ObjectType()
class DepartmentProductEdge extends Edge(Product) {}
@ObjectType()
class DepartmentProductConnection extends Connection(Product, DepartmentProductEdge) {}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.