old_contents: import {
      isEmpty, isArray, isNumber, isObject, isString, partial, defaults, isNil, isDate,
  } from 'lodash';
  import invariant from 'invariant';
  
  import { intercept } from 'mobx';
  
  import {
      field as mobxField,
      session as mobxSession,
      identifier as mobxIdentifier,
  } from 'mobx-decorated-models';
  
  const VALIDATORS = {
      number: isNumber,
      string: isString,
      array:  isArray,
      object: isObject,
      date:   isDate,
  };
  
  const COERCE = {
      date(change) {
          if (!isDate(change.newValue)) {
              change.newValue = new Date(change.newValue); // eslint-disable-line no-param-reassign
          }
      },
  };
  
  function addLazyInitializer(target, fn) {
      target.__mobxLazyInitializers.push(fn);
  }
  
  function validateChangeType(validator, propertyName, change) {
      if (isNil(change.newValue)) { return change; }
      invariant(VALIDATORS[validator], `Unknown TypeCheck: ${validator} does not exist`);
      if (COERCE[validator]) { COERCE[validator](change); }
      invariant(VALIDATORS[validator](change.newValue),
                `Bad Type: Attempted to set ${propertyName} to '${change.newValue}' which is not ${validator}`);
      return change;
  }
  
  function addTypeSafeInterceptor(target, property, type) {
      if (isEmpty(type)) { return; }
      addLazyInitializer(target, (partial(intercept, partial.placeholder, property,
                                          partial(validateChangeType, type, property))));
  }
  
  function decoratorWrapper(decorator, defaultOptions = {}) {
      return (targetOrOptions, ...args) => {
          const options = isEmpty(args) ?
                defaults(targetOrOptions, defaultOptions) : defaultOptions;
  
          const wrap = (target, property, descriptor) => {
              const decorationFn = decorator(options);
              const description = decorationFn(target, property, descriptor);
              addTypeSafeInterceptor(target, property, options.type);
              return description;
          };
  
          if (isEmpty(args)) { // we were given options
              return (target, property, descriptor) => wrap(target, property, descriptor);
          }
          return wrap(targetOrOptions, args[0], args[1]);
      };
  }
  
  const field = decoratorWrapper(mobxField);
  const session = decoratorWrapper(mobxSession);
  const identifier = decoratorWrapper(mobxIdentifier, { type: 'number' });
  
  export { field, session, identifier };
  
new_contents: import {
      isEmpty, isArray, isNumber, isObject, isString, partial, defaults, isNil, isDate,
  } from 'lodash';
  import invariant from 'invariant';
  
  import { intercept, isObservableArray, isObservableObject } from 'mobx';
  
  import {
      field as mobxField,
      session as mobxSession,
      identifier as mobxIdentifier,
  } from 'mobx-decorated-models';
  
  const VALIDATORS = {
      number: isNumber,
      string: isString,
      array(a) { return isArray(a) || isObservableArray(a); },
      object(o) { return isObject(o) || isObservableObject(o); },
      date:   isDate,
  };
  
  const COERCE = {
      date(change) {
          if (!isDate(change.newValue)) {
              change.newValue = new Date(change.newValue); // eslint-disable-line no-param-reassign
          }
      },
  };
  
  function addLazyInitializer(target, fn) {
      target.__mobxLazyInitializers.push(fn);
  }
  
  function validateChangeType(validator, propertyName, change) {
      if (isNil(change.newValue)) { return change; }
      invariant(VALIDATORS[validator], `Unknown TypeCheck: ${validator} does not exist`);
      if (COERCE[validator]) { COERCE[validator](change); }
      invariant(VALIDATORS[validator](change.newValue),
                `Bad Type: Attempted to set ${propertyName} to '${change.newValue}' which is not ${validator}`);
      return change;
  }
  
  function addTypeSafeInterceptor(target, property, type) {
      if (isEmpty(type)) { return; }
      addLazyInitializer(target, (partial(intercept, partial.placeholder, property,
                                          partial(validateChangeType, type, property))));
  }
  
  function decoratorWrapper(decorator, defaultOptions = {}) {
      return (targetOrOptions, ...args) => {
          const options = isEmpty(args) ?
                defaults(targetOrOptions, defaultOptions) : defaultOptions;
  
          const wrap = (target, property, descriptor) => {
              const decorationFn = decorator(options);
              const description = decorationFn(target, property, descriptor);
              addTypeSafeInterceptor(target, property, options.type);
              return description;
          };
  
          if (isEmpty(args)) { // we were given options
              return (target, property, descriptor) => wrap(target, property, descriptor);
          }
          return wrap(targetOrOptions, args[0], args[1]);
      };
  }
  
  const field = decoratorWrapper(mobxField);
  const session = decoratorWrapper(mobxSession);
  const identifier = decoratorWrapper(mobxIdentifier, { type: 'number' });
  
  export { field, session, identifier };
  
subject: allow array and object to be set with observables