user/entity.ts
:
import {
BaseEntity,
Entity,
PrimaryColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
BeforeInsert
} from "typeorm";
import { ObjectType, Field, ID } from "type-graphql";
import { v4 as uuid } from "uuid";
import * as bcrypt from "bcrypt";
@Entity("users")
@ObjectType()
export class User extends BaseEntity {
@PrimaryColumn("uuid")
@Field(() => ID)
id: string;
@Column("varchar", { length: 255, unique: true })
@Field()
username: string;
@Column("varchar", { length: 255 })
@Field()
password: string;
@Column("varchar", { length: 255, nullable: true })
@Field()
email?: string;
@CreateDateColumn()
created: Date;
@UpdateDateColumn()
updated: Date;
@BeforeInsert()
async setup(): Promise<void> {
this.id = uuid();
this.password = await bcrypt.hash(this.password, bcrypt.genSaltSync(12));
}
}
user/types.ts
import { createUnionType } from "type-graphql";
import { GQLErrorResponse } from "../shared/index.entity";
import { User } from "./entity";
export const RegistrationResponse = createUnionType({
name: "UserRegistrationResponse",
types: () => [User, GQLErrorResponse] as const
});
export const LoginResponse = createUnionType({
name: "UserLoginResponse",
types: () => [User, GQLErrorResponse] as const
});
export const UserQueryResponse = createUnionType({
name: "UserQueryResponse",
types: () => [User, GQLErrorResponse] as const,
resolveType: (value: User | GQLErrorResponse) => {
if ("id" in value) {
return User;
} else {
return GQLErrorResponse;
}
}
});
export const UsersQueryResponse = createUnionType({
name: "UsersQueryResponse",
types: () => [User, GQLErrorResponse] as const
});
user/resolver.ts
import { Resolver, Arg, Query, Mutation } from "type-graphql";
import * as bcrypt from "bcrypt";
import * as _ from "lodash";
import { User } from "./entity";
import { UserRegistrationInput, UserLoginInput } from "./inputs";
import { UserQueryResponse, UsersQueryResponse } from "./types";
@Resolver(User)
export class UserResolver {
@Query(() => [User])
async users(): Promise<User[]> {
return User.find({});
}
@Query(() => UserQueryResponse)
async user(
@Arg("id", { nullable: true }) id?: string
): Promise<typeof UserQueryResponse> {
const user: User | undefined = await User.findOne(id);
if (_.isEmpty(user)) {
return {
errors: [
{
path: "id",
message: "User not found"
}
]
};
}
return user as User;
}
@Mutation(() => User)
async register(@Arg("input") input: UserRegistrationInput): Promise<User> {
const user: User = await User.create(input).save();
return user;
}
@Mutation(() => User)
async login(@Arg("input") input: UserLoginInput): Promise<User> {
const user: User | undefined = await User.findOne({
where: { username: input.username }
});
const valid: boolean = await bcrypt.compare(input.password, user.password);
if (!valid) {
throw new Error("Invalid username/password");
}
return user;
}
}
但是,当我运行代码时,出现以下错误:
(node:325229) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'type' of undefined
答案 0 :(得分:0)
我发现问题是由于循环依赖,或更确切地说:导入顺序错误。
旧答案:
这只是一个猜测,因为对我来说这是问题所在:您是否尝试将id
字段的类型从ID
更改为Int
?
无论如何,在我的情况下,我在错误给出的行中更改了type-graphql
的代码时,发现了问题的根源
node:28896)UnhandledPromiseRejectionWarning:TypeError:无法读取未定义的属性'type' 在interfaceClasses.map.interfaceClass(/workspaces/assistant-private/node_modules/type-graphql/dist/schema/schema-generator.js:164:149)
因此,我进入那个schema-generator.js
并发现了这一点:
types: () => unionClassTypes.map(objectType => this.objectTypesInfo.find(type => type.target === objectType).type),
原来,objectType
已经是undefined
,所以我将其更改为:
types: () => unionClassTypes.filter(a => a).map(objectType => this.objectTypesInfo.find(type => type.target === objectType).type),
在那之后,我得到了以下错误,而不是TypeError: Cannot read property 'type' of undefined
:
GraphQLError:接口字段IBaseEntity.id期望类型为Int!但是BaseAction.id的类型为Float!。