Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

152
Visualizações
JavaScript: Merge multiple classes

I want to combine multiple classes for reusability and consistency amongst backend and frontend. Something like:

import {
  IsEmail,
  IsString,
  MaxLength,
  MinLength,
  validateSync
} from "class-validator";

class UserUsername {
  @IsString()
  @MinLength(3)
  @MaxLength(10)
  username!: string;
}

class UserEmail {
  @IsEmail()
  email!: string;
}

class UserPassword {
  @IsString()
  @MinLength(8)
  password!: string;
}

class UserSecret {
  @IsString()
  secret!: string;
}

class User /* extends UserEmail, UserUsername, UserSecret */ {}
class UserDto /* extends UserEmail, UserUsername, UserPassword */ {}

const userDto = new UserDto();

userDto.username = "noerror";
userDto.email = "error";
userDto.password = "error";

console.log(validateSync(userDto).toString());

Is something similar anyway possible?

Note: I do not mean types only like TypeScript's &. The main purpose is to reuse class validation.

Link to sandbox

The Problem:

export class User {
  @IsUUID()
  id!: string;

  @IsNotEmpty()
  @IsString()
  @MinLength(3)
  username!: string;

  @IsEmail()
  email!: string;

  @IsNotEmpty()
  @IsString()
  secret!: string;

  @IsNotEmpty()
  @IsAlpha()
  firstName!: string;

  @IsNotEmpty()
  @IsAlpha()
  lastName!: string;

  @IsBoolean()
  isEmailVerified!: boolean;
}

export class UserDto {
  @IsUUID()
  id!: string;

  @IsNotEmpty()
  @IsString()
  @MinLength(3)
  username!: string;

  @IsEmail()
  email!: string;

  secret?: never;

  @IsNotEmpty()
  @IsAlpha()
  firstName!: string;

  @IsNotEmpty()
  @IsAlpha()
  lastName!: string;

  @IsBoolean()
  isEmailVerified!: boolean;
}

export class SignUpUserDto {
  id?: never;

  @IsNotEmpty()
  @IsString()
  @MinLength(3)
  username!: string;

  @IsEmail()
  email!: string;

  secret?: never;

  @IsNotEmpty()
  @IsAlpha()
  firstName!: string;

  @IsNotEmpty()
  @IsAlpha()
  lastName!: string;

  isEmailVerified?: never;
}

export class UpdateUserDto {
  id?: never;

  @IsOptional()
  @IsNotEmpty()
  @IsString()
  @MinLength(3)
  username?: string;

  @IsOptional()
  @IsEmail()
  email?: string;

  secret?: never;

  @IsOptional()
  @IsNotEmpty()
  @IsAlpha()
  firstName?: string;

  @IsOptional()
  @IsNotEmpty()
  @IsAlpha()
  lastName?: string;

  isEmailVerified?: never;
}

export class SignInUserDto {
  @IsString()
  @IsNotEmpty()
  username!: string;

  @IsNotEmpty()
  @IsString()
  password!: string;
}

See how repetitive the code is?

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

There is a really neat way of doing this using the mixin pattern.

class UserDto {}
interface UserDto extends UserEmail, UserUsername, UserPassword {}
applyMixins(UserDto, [UserEmail, UserUsername, UserPassword]);

const userDto = new UserDto();

userDto.username = 'noerror';
userDto.email = 'error';
userDto.password = 'error';

console.log(validateSync(userDto).toString());

using this util:

function applyMixins(derivedCtor: any, constructors: any[]) {
    constructors.forEach((baseCtor) => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
            Object.defineProperty(
                derivedCtor.prototype,
                name,
                Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
                    Object.create(null)
            );
        });
    });
}
about 4 years ago · Juan Pablo Isaza Relatório

0

Thanks to Filip Kaštovský who pointed me to this doc: How Does A Mixin Work?

I got to solve it this way:

import { IsString, IsUUID, MinLength, validateSync } from 'class-validator';

type Constructor<T = {}> = new (...args: any[]) => T;

export function WithUserId<TBase extends Constructor>(Base: TBase) {
  class UserId extends Base {
    @IsUUID()
    id!: string;
  }

  return UserId;
}

export function WithUserUsername<TBase extends Constructor>(Base: TBase) {
  class UserUsername extends Base {
    @IsString()
    @MinLength(3)
    username!: string;
  }

  return UserUsername;
}

export function WithUserSecret<TBase extends Constructor>(Base: TBase) {
  class UserSecret extends Base {
    @IsString()
    secret!: string;
  }

  return UserSecret;
}

class User extends WithUserId(WithUserUsername(WithUserSecret(class {}))) {}

const user = new User();

user.id = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d";
user.username = "a";
user.secret = "a";

console.log(validateSync(user).toString());

Link to sandbox

EDIT: I cloned @nestjs/mapped-types and modified it to work in both the browser and nodejs. I wanted to publish it but I do not know a lot about publishing and whether it is actually going to work. It works fine in my set-up with Nx because I used Nx to create the library.

about 4 years ago · Juan Pablo Isaza Relatório

0

Can this achieve what you need?

Class User{
   userEmail: UserEmail;
   userUserName: UserUserName;
   userPassword: UserPassword;
}
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda