简体   繁体   English

如何在类型中传递泛型类型?

[英]How to pass a generic type in the type?

I am trying to create a new constraint for Typestack Class Validators.我正在尝试为 Typestack Class Validators 创建一个新的约束。 "IsUnique" constraint will take an Entity as the type and it's column as an argument to check if that column does not exist in the database and is unique. “IsUnique”约束将实体作为类型,并将它的列作为参数来检查该列是否在数据库中不存在并且是唯一的。

I have tried the code below but somehow I'm not being able to pass a type to the "IsUniqueConstraint" through validator key in the registerDecorator.我已经尝试了下面的代码,但不知何故我无法通过 registerDecorator 中的验证器键将类型传递给“IsUniqueConstraint” Since, I'm new to Typescript so I don't understand its concepts well.因为,我是 Typescript 的新手,所以我不太了解它的概念。

Can someone please help me to know how can we do it?有人可以帮我知道我们该怎么做吗?

is-unique.constraint.ts 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用户.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;
}

Generics are generally a compile-time-only feature. Generics 通常是仅编译时功能。 Unless you have some way of emitting the metadata, including the generics (not sure if that is easily possible).除非您有某种方式发出元数据,包括 generics(不确定这是否容易实现)。

If you need to use a type at run-time, you generally should pass it as a regular argument, so in this case the signature has to change to accommodate this:如果您需要在运行时使用类型,通常应该将其作为常规参数传递,因此在这种情况下,必须更改签名以适应这种情况:

@IsUnique(User, 'username')

This is probably why when injecting repositories you do it via @InjectRepository(User) , which also takes the entity class as argument.这可能就是为什么当你通过@InjectRepository(User)注入存储库时,它也将实体 class 作为参数。 I doubt that IsUniqueConstraint can have the repository injected as is.我怀疑IsUniqueConstraint可以按原样注入存储库。 You would probably need to resolve it from the DI container/connection manager based on the entity type passed by the decorator.您可能需要根据装饰器传递的实体类型从 DI 容器/连接管理器中解决它。

According to the docs you can directly assign an object to validator , not just a class/constructor, so you can create a concrete instance of your validator, manually passing the resolved repository to the constructor.根据文档,您可以直接将 object 分配给validator ,而不仅仅是类/构造函数,因此您可以创建验证器的具体实例,手动将解析的存储库传递给构造函数。

So, maybe something along those lines:所以,也许是这样的:

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),
        });
    };
}

Okay, after trying a lot I have solved it the other way.好的,在尝试了很多之后,我以另一种方式解决了它。 Thanks to @HB for showing me the path.感谢@HB 向我展示了路径。

To do the same I passed the entity to the validator and generated repository in the class itself.为此,我将实体传递给验证器并在 class 本身中生成存储库。 Because Nest JS Injection was working for the classes only.因为 Nest JS Injection 仅适用于类。

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,
        });
    };
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM