function SchemaArray(key, cast, options, schemaOptions) {
  // lazy load
  EmbeddedDoc || (EmbeddedDoc = require('../types').Embedded);

  let typeKey = 'type';
  if (schemaOptions && schemaOptions.typeKey) {
    typeKey = schemaOptions.typeKey;
  }
  this.schemaOptions = schemaOptions;

  if (cast) {
    let castOptions = {};

    if (utils.isPOJO(cast)) {
      if (cast[typeKey]) {
        // support { type: Woot }
        castOptions = clone(cast); // do not alter user arguments
        delete castOptions[typeKey];
        cast = cast[typeKey];
      } else {
        cast = Mixed;
      }
    }

    if (options != null && options.ref != null && castOptions.ref == null) {
      castOptions.ref = options.ref;
    }

    if (cast === Object) {
      cast = Mixed;
    }

    // support { type: 'String' }
    const name = typeof cast === 'string'
      ? cast
      : utils.getFunctionName(cast);

    const Types = require('./index.js');
    const caster = Types.hasOwnProperty(name) ? Types[name] : cast;

    this.casterConstructor = caster;

    if (this.casterConstructor instanceof SchemaArray) {
      this.casterConstructor[isNestedArraySymbol] = true;
    }

    if (typeof caster === 'function' &&
        !caster.$isArraySubdocument &&
        !caster.$isSchemaMap) {
      const path = this.caster instanceof EmbeddedDoc ? null : key;
      this.caster = new caster(path, castOptions);
    } else {
      this.caster = caster;
      if (!(this.caster instanceof EmbeddedDoc)) {
        this.caster.path = key;
      }
    }

    this.$embeddedSchemaType = this.caster;
  }

  this.$isMongooseArray = true;

  SchemaType.call(this, key, options, 'Array');

  let defaultArr;
  let fn;

  if (this.defaultValue != null) {
    defaultArr = this.defaultValue;
    fn = typeof defaultArr === 'function';
  }

  if (!('defaultValue' in this) || this.defaultValue != null) {
    const defaultFn = function() {
      // Leave it up to `cast()` to convert the array
      return fn
        ? defaultArr.call(this)
        : defaultArr != null
          ? [].concat(defaultArr)
          : [];
    };
    defaultFn.$runBeforeSetters = !fn;
    this.default(defaultFn);
  }
}
Array SchemaType constructor

@param {String} key
@param {SchemaType} cast
@param {Object} options
@param {Object} schemaOptions
@inherits SchemaType
@api public