code: function doArgs(values, types) {
    let value, type, carry, optional, defaultValue;
    const result = [];
  
    for (type of types) {
      // Load value if we don't have one already
      if (!carry) {
        value = Array.prototype.shift.call(values);
      }
  
      // Handle optional type
      if (Array.isArray(type)) {
        optional = true;
        defaultValue = type[1];
        type = type[0];
      } else {
        optional = false;
      }
  
      // Handle multitype
      type = type.split('|');
  
      // Is it a correct value?
      if (type.includes(getType(value))) {
        result.push(value);
        carry = false;
      } else if (optional) {
        result.push(defaultValue);
        carry = true;
      } else {
        throw Error('Invalid arguments');
      }
    }
    if (values.length) {
      // TODO maybe do some warning..?
      // throw Error('Extra arguments ' + values.length, values);
    }
    return result;
  }
docs: Processes arguments according to the rules defined by the types array.
  Types of arguments are checked, optional arguments are replaced by their
  default values or left undefined.
  
  @param {arguments} values: The arguments object.
  @param {array} types: Array of types, see below.
  @returns {array} the processed arguments in an array.
  @throws {Error} if arguments don't fit, throws an error.
  
  Examples of types:
  ['string']             - function requires one string
  ['string', ['number']] - function requires one string and expects an optional number
  [['object', {}]]       - function expects an optional object defaulting to empty object
  ['string|array']       - function requires string or array
  
  Inspired by
  See: https://www.npmjs.com/package/assert-args
  See: https://www.npmjs.com/package/ensurethat