【问题标题】:How to pass a generic type in the type?如何在类型中传递泛型类型?
【发布时间】:2020-02-05 23:50:16
【问题描述】:

我正在尝试为 Typestack 类验证器创建一个新的约束。 “IsUnique” 约束将实体作为类型,并将其列作为参数来检查该列是否在数据库中不存在并且是唯一的。

我尝试了下面的代码,但不知何故,我无法通过 registerDecorator 中的验证器键将类型传递给 "IsUniqueConstraint"。因为,我是 Typescript 的新手,所以我不太了解它的概念。

有人可以帮我知道我们该怎么做吗?

is-unique.constraint.ts

import { registerDecorator, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, ValidationOptions } from 'class-validator';
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';

@ValidatorConstraint({ name: 'isUnique', async: true })
@Injectable()
export class IsUniqueConstraint<T> implements ValidatorConstraintInterface {

    constructor(private readonly repository: Repository<T>) { }

    async validate(value: string, args: ValidationArguments) {
        const [column] = args.constraints;

        const result = await this.repository.findOne({ where: { [column]: value } });

        if (result) {
            return false;
        }

        return true;
    }

    defaultMessage(args: ValidationArguments) {
        return `"${args.value}" already exists for ${args.constraints[0]}`;
    }

}

export function IsUnique<T>(column: string, validationOptions?: ValidationOptions) {
    return (object: object, propertyName: string) => {
        registerDecorator({
            target: object.constructor,
            propertyName,
            options: validationOptions,
            constraints: [column],
            validator: IsUniqueConstraint,
        });
    };
}

user.dto.ts

import { IsNotEmpty } from 'class-validator';
import { IsUnique } from './../shared/constraints/is-unique.constraint';
import { User } from './user.entity';

export class CreateUserDto {
  @IsNotEmpty()
  @IsUnique<User>('username')
  readonly username: string;
}

【问题讨论】:

    标签: javascript typescript generics decorator class-validator


    【解决方案1】:

    好的,在尝试了很多之后,我以另一种方式解决了它。感谢@H.B。给我指路。

    为了做同样的事情,我将实体传递给验证器并在类本身中生成存储库。因为 Nest JS 注入仅适用于类。

    import { registerDecorator, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, ValidationOptions } from 'class-validator';
    import { Injectable } from '@nestjs/common';
    import { Connection } from 'typeorm';
    import { InjectConnection } from '@nestjs/typeorm';
    
    @ValidatorConstraint({ name: 'isUnique', async: true })
    @Injectable()
    export class IsUniqueConstraint implements ValidatorConstraintInterface {
    
        constructor(@InjectConnection() private readonly connection: Connection) { }
    
        async validate(value: string, args: ValidationArguments) {
            const [entity, column] = args.constraints;
    
            const repository = this.connection.getRepository(entity);
            const result     = await repository.findOne({ where: { [column]: value } });
    
            if (result) {
                return false;
            }
    
            return true;
        }
    
        defaultMessage(args: ValidationArguments) {
            return `"${args.value}" already exists for ${args.constraints[1]}`;
        }
    
    }
    
    export function IsUnique(entity: Function, column: string, validationOptions?: ValidationOptions) {
        return (object: object, propertyName: string) => {
            registerDecorator({
                target: object.constructor,
                propertyName,
                options: validationOptions,
                constraints: [entity, column],
                validator: IsUniqueConstraint,
            });
        };
    }
    

    【讨论】:

      【解决方案2】:

      泛型通常是仅编译时的功能。除非您有某种方式发出元数据,包括泛型(不确定这是否容易实现)。

      如果您需要在运行时使用类型,通常应该将其作为常规参数传递,因此在这种情况下,必须更改签名以适应这种情况:

      @IsUnique(User, 'username')
      

      这可能就是为什么在注入存储库时您通过@InjectRepository(User) 执行此操作,它也将实体类作为参数。我怀疑IsUniqueConstraint 可以按原样注入存储库。您可能需要根据装饰器传递的实体类型从 DI 容器/连接管理器中解决它。

      根据文档,您可以直接将对象分配给validator,而不仅仅是类/构造函数,因此您可以创建验证器的具体实例,手动将解析的存储库传递给构造函数。

      所以,也许是这样的:

      import { getRepository } from "typeorm";
      // ...
      
      export function IsUnique(
          entity: Function,
          column: string,
          validationOptions?: ValidationOptions) {
      
          // Not sure if this works here. Maybe it needs to be
          // moved into the returned function or a different resolution
          // mechanism is required.
          const repository = getRepository(entity); 
      
          return (object: object, propertyName: string) => {
              registerDecorator({
                  target: object.constructor,
                  propertyName,
                  options: validationOptions,
                  constraints: [column],
                  validator: new IsUniqueConstraint(repository),
              });
          };
      }
      

      【讨论】:

      • getRepository 抛出一个错误,提示:未找到连接“默认”。有什么办法可以解决吗?你能为此分享一个示例代码吗?谢谢。
      • 如果您不使用默认连接,则需要找出您(可能隐含地)使用的连接。如果您使用的是默认连接,则呼叫时间可能不正确,因此必须移动它。对不起,我不能给你具体的代码。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-07
      • 2016-02-12
      • 1970-01-01
      相关资源
      最近更新 更多