mobxjs / serializr

Serialize and deserialize complex object graphs to and from JSON and Javascript classes
MIT License
766 stars 52 forks source link

Plain JSON serializable object inside serializable class #50

Closed xaviergonz closed 7 years ago

xaviergonz commented 7 years ago

Given something like

export class SomeClass {
  // .. some other serializable properties

  @serializable(map(primitive())) // primitive does not work with objects, what do I use?
  subObject: {
    [id: string]: any;
  } = {};
}

where each key of subObject may contain either primitives or any kind of objects, and being this subObject JSON serializable, what @serializable attribute do I need to make it work? I tried map(primitives()), but it complains when any of the values are objects instead of primitives

Is there something like map(any()), object(any()) or some such?

xaviergonz commented 7 years ago

Ok, I managed to do it using @serializable(custom((val) => val, (val) => val)) Is there a shortcut for this that I missed? If not I think it would be nice if there was, like a json() PropSchema, or any()

xaviergonz commented 7 years ago

Just in case it might be useful for someone else I made the following helper PropSchemas

/**
 * Prop schema for JSON serializable values.
 * @param restrictionChecker function to check for possible restrictions.
 * @return {PropSchema}
 */
export const jsonValue = (restrictionChecker?: (value: any) => string | undefined): PropSchema => {
  const convert = (v: any, errorMessage: string) => {
    if (restrictionChecker) {
      const err =  restrictionChecker(v);
      if (err !== undefined && err !== null) {
        throw new Error(errorMessage + err);
      }
    }
    return v;
  };

  const modelToJson = (v: any) => {
    return convert(v, 'serialization error: ');
  };

  const jsonToModel = (v: any) => {
    return convert(v, 'deserialization error: ');
  };

  return custom(modelToJson, jsonToModel);
};

/**
 * Prop schema for non-null JSON-serializable objects.
 * @param restrictionChecker function to check for possible restrictions.
 * @return {PropSchema}
 */
export const jsonObject = (restrictionChecker?: (value: any) => string | undefined): PropSchema => {
  const composedRestrictionChecker = (value: any) => {
    if (typeof value !== 'object' || value === null || Array.isArray(value)) {
      return 'not an object';
    }

    if (restrictionChecker) return restrictionChecker(value);
    return undefined;
  };

  return jsonValue(composedRestrictionChecker);
};
alexggordon commented 7 years ago

Closing this, I think a custom type is the best way to solve this