为什么 TypeGraphQL 不能确定泛型的类型?
Why can't TypeGraphQL determine the type of a generic?
我正在尝试为在 GraphQL 中构建连接和边缘定义通用类型定义。除了为了方便起见,我还包括了常规的 nodes
连接 属性 之外,我与 Relay 规范保持一致。 TypeGraphQL docs 展示了如何做一些非常相似的事情,但是当我尝试 运行 服务器时出现以下错误:
Cannot determine GraphQL output type for 'nodes' of 'Connection' class. 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?
通常,当 class 定义中缺少 @ObjectType
装饰器时会出现这种情况,然后在其他地方将其用作字段类型;但是,我已经确认我传递的类型肯定是用这个装饰器定义的,而且我也尝试过使用我的模式中的几种不同类型。文档演示了使用泛型作为字段定义,因此这似乎也不是问题。
我的类型定义如下:
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
}
编辑:以下解决方法解决了类型问题,这证明传入的类型在其定义中具有正确的装饰器。但是,这非常笨重,所以我想尽可能避免使用它。
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[]
}
上下文,对于任何好奇的人:
所有这一切的目的是使用类似这样的东西生成连接...
type RawDepartmentProductEdge = RawEdge<Product>
@ObjectType()
class DepartmentProductEdge extends Edge(Product) {}
@ObjectType()
class DepartmentProductConnection extends Connection(Product, DepartmentProductEdge) {}
...然后像这样填充它们...
const products = [] // Retrieve the products here
const edges = products.map(node => new DepartmentProductEdge(node.id, node)
const connection = new DepartmentProductConnection(edges, pagination)
...所以一切都尽可能干燥,但我仍然可以根据需要向边缘添加元数据。
事实证明,上面的代码工作得很好:问题出在对我的导入进行排序。我正在使用一个“桶”文件来导出我所有的 GraphQL 类型,虽然这可以很好地将它们带入解析器或中间件,但从类型定义中的桶导入会导致奇怪的循环依赖问题。
解决方法就是在进行类型声明时直接从源文件中导入类型。因此,特别适用于上面的示例:
// 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) {}
我正在尝试为在 GraphQL 中构建连接和边缘定义通用类型定义。除了为了方便起见,我还包括了常规的 nodes
连接 属性 之外,我与 Relay 规范保持一致。 TypeGraphQL docs 展示了如何做一些非常相似的事情,但是当我尝试 运行 服务器时出现以下错误:
Cannot determine GraphQL output type for 'nodes' of 'Connection' class. 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?
通常,当 class 定义中缺少 @ObjectType
装饰器时会出现这种情况,然后在其他地方将其用作字段类型;但是,我已经确认我传递的类型肯定是用这个装饰器定义的,而且我也尝试过使用我的模式中的几种不同类型。文档演示了使用泛型作为字段定义,因此这似乎也不是问题。
我的类型定义如下:
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
}
编辑:以下解决方法解决了类型问题,这证明传入的类型在其定义中具有正确的装饰器。但是,这非常笨重,所以我想尽可能避免使用它。
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[]
}
上下文,对于任何好奇的人:
所有这一切的目的是使用类似这样的东西生成连接...
type RawDepartmentProductEdge = RawEdge<Product>
@ObjectType()
class DepartmentProductEdge extends Edge(Product) {}
@ObjectType()
class DepartmentProductConnection extends Connection(Product, DepartmentProductEdge) {}
...然后像这样填充它们...
const products = [] // Retrieve the products here
const edges = products.map(node => new DepartmentProductEdge(node.id, node)
const connection = new DepartmentProductConnection(edges, pagination)
...所以一切都尽可能干燥,但我仍然可以根据需要向边缘添加元数据。
事实证明,上面的代码工作得很好:问题出在对我的导入进行排序。我正在使用一个“桶”文件来导出我所有的 GraphQL 类型,虽然这可以很好地将它们带入解析器或中间件,但从类型定义中的桶导入会导致奇怪的循环依赖问题。
解决方法就是在进行类型声明时直接从源文件中导入类型。因此,特别适用于上面的示例:
// 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) {}