英文:
How can I correctly type the return value from a Postgres database in TypeORM with NestJS?
问题
# 如何正确地输入从postgres数据库返回的值
有人可以解释一下这一点吗?我在使用PostgreSQL、Nest和TypeORM方面还很新手,我想创建一个基本的CRUD应用程序。我对在TypeORM中进行输入方面有一个问题。
我的用户实体:
```typescript
@Entity('user')
export class UserEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@Column({
type: 'varchar',
})
name: string;
@Column({
type: 'varchar',
})
password: string;
@Column({
nullable: true,
type: 'varchar',
default: () => 'NULL',
})
refreshToken: string;
}
我的用户服务:
@Injectable()
export class UsersService {
constructor(
@InjectRepository(UserEntity)
private usersRepository: Repository<UserEntity>,
) {}
createUser(createUserDto: SignUpDto) {
return this.usersRepository.save(createUserDto);
}
findAllUsers() {
return this.usersRepository.find({
select: ['id', 'email', 'name'],
});
}
findUserById(id: number) {
return this.usersRepository
.createQueryBuilder('user')
.select([
'user.id',
'user.email',
'user.name',
])
.where('user.id= :userId', { userId: id })
.getOne();
}
findUserByEmail(email: string) {
return this.usersRepository.findOneBy({ email });
}
}
FindUserById
是一个外部方法(有一个控制器方法调用它)。它返回一个具有不完整数据的用户,没有密码和refreshToken字段(我认为它们不应该暴露)。
FindUserByEmail
是一个内部方法,被另一个服务(authService
)使用。它返回完整的用户数据。
问题在于推断的返回类型在两种情况下都是Promise<UserEntity>
,我不明白这怎么能适应这两个函数。
首先,我认为推断类型至少应该是Promise<UserEntity | null>
。但它不是。
其次,我以为TypeORM会自动推断数据类型。问题是,TypeORM实际上能做到吗?如果不能,我应该如何正确地为返回值定义类型?创建多个不同的数据类型吗?使用Omit
吗?通过添加可选字段来为UserEntity
类型定义类型吗?我不明白。
<details>
<summary>英文:</summary>
# How to correctly type the value returned from the postgres database
Can anyone please explane this moment. I'm new at postgresql, nest and typeorm, and i want to create primitive CRUD application. I have a question about typing at typeorm.
My User Entity:
@Entity('user')
export class UserEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@Column({
type: 'varchar',
})
name: string;
@Column({
type: 'varchar',
})
password: string;
@Column({
nullable: true,
type: 'varchar',
default: () => 'NULL',
})
refreshToken: string;
}
My UserService:
@Injectable()
export class UsersService {
constructor(
@InjectRepository(UserEntity)
private usersRepository: Repository<UserEntity>,
) {}
createUser(createUserDto: SignUpDto) {
return this.usersRepository.save(createUserDto);
}
findAllUsers() {
return this.usersRepository.find({
select: ['id', 'email', 'name'],
});
}
findUserById(id: number) {
return this.usersRepository
.createQueryBuilder('user')
.select([
'user.id',
'user.email',
'user.name',
])
.where('user.id= :userId', { userId: id })
.getOne();
}
findUserByEmail(email: string) {
return this.usersRepository.findOneBy({ email });
}
}
**`FindUserById`** is external method (there is a controller method that calls it) . It returns a user with incomplete data without password and refreshToken fields ( I don't think they should be exposed).
**`FindUserByEmail`** is an internal method that is used by another service (`authService`). It returns the complete user data.
The problem is that the inferred return type is `Promise<UserEntity>` in both cases, and I don't see how that could fit both functions.
First, I think the inferred type should be at least `Promise<UserEntity | null>`. But it's not.
Second, I thought TypeORM would automatically infer the data type. The question is, can TypeORM actually do this? And if not, how do I correctly type return values then? Create multiple different data types? Use `Omit`? Type `UserEntity` by adding optional fields? I don't understand.
</details>
# 答案1
**得分**: 0
The problem is that the inferred return type is `Promise<UserEntity>` in both cases, and I don't see how that could fit both functions.
问题在于推断的返回类型在两种情况下都是`Promise<UserEntity>`,我不明白如何适应这两个函数。
First, I think the inferred type should be at least `Promise<UserEntity | null>`. But it's not.
首先,我认为推断的类型至少应该是`Promise<UserEntity | null>`。但它不是。
You're correct. The options are either it finds it in the db and resolves with `UserEntity`, or it doesn't find it and resolves with `null`.
你说得对。选项要么在数据库中找到它并解析为`UserEntity`,要么找不到并解析为`null`。
`UserEntity` is an object. Any object can be `null`. Therefore `UserEntity | null` is the same as just `UserEntity`.
`UserEntity` 是一个对象。任何对象都可以是 `null`。因此 `UserEntity | null` 和 `UserEntity` 是一样的。
Second, I thought TypeORM would automatically infer the data type. The question is, can TypeORM actually do this? And if not, how do I correctly type return values then? Create multiple different data types? Use Omit? Type UserEntity by adding optional fields? I don't understand.
其次,我以为 TypeORM 会自动推断数据类型。问题是,TypeORM 真的能做到吗?如果不能,那么如何正确地为返回值添加类型?创建多个不同的数据类型?使用 Omit?通过添加可选字段来为 UserEntity 添加类型?我不明白。
TypeORM infers the return type with the assumption that you return the full entity (don't do any `select`s). Since you know more than TypeORM when writing your `UsersService`, you're responsible for specifying more precise type information if you want to. `Partial`/`Omit`/`Pick` are good options for this.
TypeORM 推断返回类型的前提是你返回完整的实体(不要使用任何 `select`)。由于在编写 `UsersService` 时,你比 TypeORM 更了解情况,因此如果需要,你需要负责指定更精确的类型信息。`Partial`/`Omit`/`Pick` 都是这方面的好选项。
<details>
<summary>英文:</summary>
> The problem is that the inferred return type is `Promise<UserEntity>` in both cases, and I don't see how that could fit both functions.
> First, I think the inferred type should be at least `Promise<UserEntity | null>`. But it's not.
You're correct. The options are either it finds it in the db and resolves with `UserEntity`, or it doesn't find it and resolves with `null`.
`UserEntity` is an object. Any object can be `null`. Therefore `UserEntity | null` is the same as just `UserEntity`.
> Second, I thought TypeORM would automatically infer the data type. The question is, can TypeORM actually do this? And if not, how do I correctly type return values then? Create multiple different data types? Use Omit? Type UserEntity by adding optional fields? I don't understand.
TypeORM infers the return type with the assumption that you return the full entity (don't do any `select`s). Since you know more than TypeORM when writing your `UsersService`, you're responsible for specifying more precise type information if you want to. `Partial`/`Omit`/`Pick` are good options for this.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论