You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中如何在ObjectType字段注解中使用泛型声明?自定义GraphQL分页结果报错求助

Fixing Undefined Type Error for Generic PaginateResult in NestJS GraphQL

The error you're seeing happens because TypeGraphQL can't infer the runtime type of the generic T in your PaginateResult class. GraphQL requires explicit type definitions for all fields, and since TypeScript generics are erased at compile time, the docs field doesn't have a concrete type attached to it in the schema.

Here are two approaches to solve this:

Approach 1: Create a Concrete Paginated Result Class (Simple)

For each type you want to paginate (like User), create a dedicated ObjectType class that explicitly defines the docs field type.

Step 1: Define User-Specific Pagination Result

import { ObjectType, Field } from '@nestjs/graphql';
import { User } from './user.entity'; // Adjust import path as needed

@ObjectType()
export class UserPaginateResult {
  // Explicitly set the type to an array of User
  @Field(() => [User])
  docs: User[];

  @Field()
  totalDocs: string;

  @Field()
  totalPages: string;
}

Step 2: Update the Resolver to Use the Concrete Type

@Query((type) => UserPaginateResult, { nullable: true })
async getUsers(@Args({ type: () => GetAllUserArgs }) args: GetAllUserArgs) {
  const queryResolver: QueryResolver = new QueryResolver(args);
  return this.userService.getAll(queryResolver.query);
}

This works because we've replaced the generic PaginateResult<User> with a concrete class that tells TypeGraphQL exactly what type docs should be.

Approach 2: Reusable Factory Function (Scalable)

If you need to paginate multiple types, creating a new class for each gets repetitive. Instead, use a factory function to dynamically generate paginated result types for any object type.

Step 1: Create a Paginate Result Factory

import { ObjectType, Field, Type } from '@nestjs/graphql';

// Define a base interface for pagination results
export interface PaginateResult<T> {
  docs: T[];
  totalDocs: string;
  totalPages: string;
}

// Factory function to generate paginated result types
export function PaginateResultFactory<T>(itemType: Type<T>) {
  // Generate a unique name for the GraphQL type (e.g., "UserPaginateResult")
  @ObjectType(`${itemType.name}PaginateResult`)
  class PaginateResultClass implements PaginateResult<T> {
    @Field(() => [itemType])
    docs: T[];

    @Field()
    totalDocs: string;

    @Field()
    totalPages: string;
  }

  return PaginateResultClass;
}

Step 2: Use the Factory in Your Resolver

@Query((type) => PaginateResultFactory(User), { nullable: true })
async getUsers(@Args({ type: () => GetAllUserArgs }) args: GetAllUserArgs) {
  const queryResolver: QueryResolver = new QueryResolver(args);
  return this.userService.getAll(queryResolver.query);
}

Now you can reuse this factory for any type:

// For a Product type, for example
@Query((type) => PaginateResultFactory(Product), { nullable: true })
async getProducts(...) { /* ... */ }

Bonus: Optional Type Improvement

Note that totalDocs and totalPages are typically numeric values. If these are supposed to be numbers instead of strings, you should update their types to number and use the Int scalar for GraphQL:

import { Int } from '@nestjs/graphql';

// In your paginate result class/factory:
@Field(() => Int)
totalDocs: number;

@Field(() => Int)
totalPages: number;

This will make your schema more accurate and avoid unnecessary string-to-number conversions.

内容的提问来源于stack exchange,提问作者masood keshvari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 03:17:37