使用TypeScript装饰器定义嵌套对象GraphQL Schema及报错解决
问题描述
需要为如下JSON结构编写TypeScript嵌套对象Schema:
{ "firstname": "Jhon", "lastname": "Doe", "adress": { "street": "Park Avenue", "city": "New York", "zipcode": "97000" }, "active": true }
尝试使用TypeScript装饰器(结合NestJS + Mongoose + GraphQL)实现,定义User类后添加Adress嵌套类,执行时触发错误:
Error: Schema must contain uniquely named types but contains multiple types named "Adress".
尝试的错误代码
User类
@Schema({ timestamps: true }) @ObjectType() export class User { @Field(() => String) _id: MongooseSchema.Types.ObjectId; @Prop({ type: String, required: true }) @Field(() => String, { description: 'First Name' }) firstname: string; @Prop({ type: String, required: true }) @Field(() => String, { description: 'Last Name' }) lastname: string; // 错误的地址对象引用 @Prop({ type: Adress }) @Field(() => Adress, { description: 'User Address' }) adores: Adress; @Prop({ type: Boolean, default: true }) @Field(() => Boolean, { description: 'User status' }) active: boolean; } export const UserSchema = SchemaFactory.createForClass(User);
Adress类
@Schema({ _id: false }) @ObjectType() export class Adress { @Prop({ type: String }) @Field(() => String, { nullable: true, description: 'Street' }) street?: string; @Prop({ type: String }) @Field(() => String, { nullable: true, description: 'City' }) city?: string; @Prop({ type: String }) @Field(() => String, { nullable: true, description: 'Zip Code' }) zipcode?: string; }
问题原因
- Mongoose嵌套Schema引用错误:在
@Prop装饰器中直接传入Adress类是错误的,Mongoose需要的是子Schema实例,而非类本身。 - 拼写不一致:User类中属性名写成了
adores(应为address),虽不是直接报错原因,但会导致字段不匹配。 - GraphQL类型重复:如果
Adress类被重复定义或在多模块重复导入,会导致@ObjectType生成重复的GraphQL类型名称,触发报错。
正确实现方案
步骤1:定义并导出嵌套地址Schema
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose'; import { ObjectType, Field } from '@nestjs/graphql'; @Schema({ _id: false }) // 禁用子文档自动生成_id @ObjectType() export class Address { // 统一拼写为Address,避免混淆 @Prop({ type: String }) @Field(() => String, { nullable: true, description: 'Street' }) street?: string; @Prop({ type: String }) @Field(() => String, { nullable: true, description: 'City' }) city?: string; @Prop({ type: String }) @Field(() => String, { nullable: true, description: 'Zip Code' }) zipcode?: string; } // 生成Address对应的Mongoose Schema实例 export const AddressSchema = SchemaFactory.createForClass(Address);
步骤2:在User类中正确引用嵌套Schema
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose'; import { ObjectType, Field } from '@nestjs/graphql'; import { Address, AddressSchema } from './address.entity'; // 统一导入地址类和Schema @Schema({ timestamps: true }) @ObjectType() export class User { @Field(() => String) _id: MongooseSchema.Types.ObjectId; @Prop({ type: String, required: true }) @Field(() => String, { description: 'First Name' }) firstname: string; @Prop({ type: String, required: true }) @Field(() => String, { description: 'Last Name' }) lastname: string; // 正确引用嵌套的Address Schema @Prop({ type: AddressSchema }) @Field(() => Address, { description: 'User Address' }) address: Address; // 修正属性名为address @Prop({ type: Boolean, default: true }) @Field(() => Boolean, { description: 'User status' }) active: boolean; } export const UserSchema = SchemaFactory.createForClass(User);
简化写法(无需单独导出AddressSchema)
如果不需要单独使用AddressSchema,可以直接在@Prop中生成:
@Prop({ type: SchemaFactory.createForClass(Address) }) @Field(() => Address, { description: 'User Address' }) address: Address;
内容的提问来源于stack exchange,提问作者Pillo
相关产品推荐
相关产品推荐

