JavaScript:合并多个类
JavaScript: Merge multiple classes
我想合并多个 classes 以实现后端和前端之间的可重用性和一致性。类似于:
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());
有类似的东西吗?
注意: 我的意思并不是像 TypeScript 那样的类型 &
。主要目的是重用class验证。
问题:
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;
}
看到代码的重复程度了吗?
这样能达到你需要的吗?
Class User{
userEmail: UserEmail;
userUserName: UserUserName;
userPassword: UserPassword;
}
我认为你的代码这样更有意义(并解决问题):
If you really need join three classes, you could try mixins: https://javascript.info/mixins
class UserLogin {
@IsString()
@MinLength(3)
@MaxLength(10)
username!: string;
@IsEmail()
email!: string;
}
class UserPassword {
@IsString()
@MinLength(8)
password!: string;
}
class UserSecret {
@IsString()
secret!: string;
}
class User extends UserSecret {
/// Secret things here...
}
class UserDto extends UserPassword {
/// Password things here...
}
使用 mixin 模式有一种非常巧妙的方法。
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());
使用此实用程序:
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)
);
});
});
}
感谢 Filip Kaštovský 向我指出了这个文档:How Does A Mixin Work?
我必须这样解决:
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());
编辑:
我克隆了 @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.
我想合并多个 classes 以实现后端和前端之间的可重用性和一致性。类似于:
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());
有类似的东西吗?
注意: 我的意思并不是像 TypeScript 那样的类型 &
。主要目的是重用class验证。
问题:
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;
}
看到代码的重复程度了吗?
这样能达到你需要的吗?
Class User{
userEmail: UserEmail;
userUserName: UserUserName;
userPassword: UserPassword;
}
我认为你的代码这样更有意义(并解决问题):
If you really need join three classes, you could try mixins: https://javascript.info/mixins
class UserLogin {
@IsString()
@MinLength(3)
@MaxLength(10)
username!: string;
@IsEmail()
email!: string;
}
class UserPassword {
@IsString()
@MinLength(8)
password!: string;
}
class UserSecret {
@IsString()
secret!: string;
}
class User extends UserSecret {
/// Secret things here...
}
class UserDto extends UserPassword {
/// Password things here...
}
使用 mixin 模式有一种非常巧妙的方法。
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());
使用此实用程序:
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)
);
});
});
}
感谢 Filip Kaštovský 向我指出了这个文档:How Does A Mixin Work?
我必须这样解决:
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());
编辑: 我克隆了 @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.