Giter Site home page Giter Site logo

Comments (6)

AmauryD avatar AmauryD commented on August 17, 2024

Hello,

It's strange indeed, i use the SchemaBase syntax in my projects but i don't have this kind of behavior on my side.
Thank's for submitting a fix, but i'll check on my side if there's not another way to fix the problem. By taking a quick glance, your pull requests seems a bit "hacky" to me atm.

I'll take a closer look at it at the end of the week. I'll keep you informed !

from fastest-validator-decorators.

ispyinternet avatar ispyinternet commented on August 17, 2024

Great thanks

from fastest-validator-decorators.

AmauryD avatar AmauryD commented on August 17, 2024

The problem

class SchemaBase {
    constructor(props: any) {
       Object.assign(this, props);
    }
 }
 
 class Test extends SchemaBase {
   prop!: string; // undefined
 }
 const email = new Test({prop: "[email protected]"});
 
 console.log(email); // <-- Test { prop: undefined }

The reason it is not working is that the parent constructor is called before the child constructor. The defined properties in the child override the parent properties with undefined.

The behavior is well described in this StackOverflow post : https://stackoverflow.com/questions/56790983/object-assigned-in-base-class-does-not-change-the-child-class

Why it was working in my projects :

class Test extends SchemaBase {
  declare prop: string; // does not exists
}

I use declare instead of the !. The difference is that ! seems to create the property with undefined and declare just tells typescript that the property will exists, so it is not overridden by the child class.

Why it is working in the tests

It seems that the ! in the tests behaves like the declare keyword for an unknown reason. It may depends on the typescript transpiler.

The solution

There are 3 ways to solve the problem :

  • use declare

  • don't use the SchemaBase syntax

  • The code below

import { Email, Schema, SchemaBase } from "fastest-validator-decorators";

function PatchConstructor () {
  return function _DecoratorName<T extends {new (...args: any[]): {}}>(constr: T) {
    if (constr.prototype instanceof SchemaBase) {
      return class extends constr {
        constructor (...args: any[]) {
          super(...args)
          Object.assign(this, args[0]);
        }
      }
    }
    return constr;
  }
}

@PatchConstructor()
@Schema()
class Test extends SchemaBase {
  @Email() 
  prop: string;
}

const email = new Test({prop: "[email protected]"})

console.log("email class before validation", email);

const result = email.validate();

console.log("validation result", result);

console.log("email class after validation", email);

I'll probably apply a similar patch to the Schema constructor.

export function Schema (schemaOptions?: StrictMode | SchemaOptions, messages = {}): any {
  return function _Schema<T extends {new (): any}>(target: any): any {
    /**
     * Support old way of assign schema options
     */
    schemaOptions = typeof schemaOptions === "boolean" ||  typeof schemaOptions === "string" ? {
      strict : schemaOptions
    }: schemaOptions;

    if (target.prototype instanceof SchemaBase) {
      target = class extends target {
        constructor (...args: any[]) {
          super(...args);
          Object.assign(this, args[0]);
        }
      };
    }

    updateSchema(target.prototype, "$$strict", schemaOptions?.strict ?? false);
    if (schemaOptions?.async !== undefined) {
      updateSchema(target.prototype, "$$async", schemaOptions.async);
    }
  
    const s = getSchema(target);
    const v = new FastestValidator({ useNewCustomCheckerFunction: true, messages });

    /**
     * Make a copy of the schema, in order to keep the original from being overriden or deleted by fastest-validator
     * $$async key is removed from schema object at compile()
     * https://github.com/icebob/fastest-validator/blob/a746f9311d3ebeda986e4896d39619bfc925ce65/lib/validator.js#L176
     */
    Reflect.defineMetadata(COMPILE_KEY, v.compile({...s}), target);
    

    return target;
  };
}

With this patch the tests pass except one : "should preserve the constructor name on instancies". i'm still thinking how to solve that problem.

I will maybe remove the SchemaBase syntax in version 2.x. And let the user deal with the way he assigns the properties on the class.

from fastest-validator-decorators.

AmauryD avatar AmauryD commented on August 17, 2024

I created a new release named 1.3.1-beta.0. You can check if it fixes the problem on your side.

Your Pull Request #28 was working fine in the tests but the properties were lost until the Object was validated. So it'll probably break some things in production.

I added a test for this case :

it("SchemaBase with @Schema should override already defined properties", () => {

from fastest-validator-decorators.

ispyinternet avatar ispyinternet commented on August 17, 2024

Hi yes this works. If you were to remove SchemaBase in the future is it just a case of...

const data = { ...props };
const mySchema = new DataSchema();
Object.assign(mySchema, data);

I mean that is ok, but as it stands when extending SchemaBase its super clean and succint.

from fastest-validator-decorators.

AmauryD avatar AmauryD commented on August 17, 2024

I'm still not sure about removing the SchemaBase or not ... We will see in the future !
I'm closing the ticket, thank you for your contribution !

from fastest-validator-decorators.

Related Issues (14)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.