import { MinLengthError } from './errors' import { ValueObject, ValueObjectContructor, VOCRawInit, VORaw } from './value-object' export interface VOAnyInstance> { readonly value: VO valueOf(): VORaw } export interface VOAnyConstructor { new (r: VOCRawInit): VOAnyInstance> } /** * Function to create a value object constructor with many inner value * object constructors to attempt instantiation. * Useful if you're expecting one of many value objects. * * @template VOC Value object constructor type to make an wrapper of. * @param VOCs Array of value object constructor to attempt instantiation in order. * @return Class constructor that accepts all that the inner value object * constructors would accept and tries to instantiate one of the inner * value object constructors in the order that they were given. * The class created by `VOAny` wraps the inner classes and * exposes the one used for instantiation through the `.value` * property. Calling {@link VOAnyInstance.valueOf} will call * `valueOf()` for that inner class. * * @example * ```typescript * class Email { ... } * class UserName { ... } * class EmailOrUserName extends VOAny([Email, UserName]) {} * * new EmailOrUserName('lucas@example.com').value // Email * new EmailOrUserName('lucas').value // UserName * ``` */ export const VOAny = (VOCs: Array): VOAnyConstructor => { if (VOCs.length < 1) throw new MinLengthError(1, VOCs.length) return class { public readonly value: InstanceType constructor(raw: VOCRawInit) { const errors: Array = [] for (const VO of VOCs) { try { const valueObject = >new VO(raw) this.value = valueObject return } catch (err) { errors.push(err) } } throw errors } valueOf(): VORaw> { return this.value.valueOf() } } }