function registerMethods(methods, type) {
  for (const methodName in methods) {
    if (!methods.hasOwnProperty(methodName)) {
      return;
    }
    if (hasConflictingRegistration(methodName, type)) {
      let msg = `There is a conflicting registration for method with name "${methodName}".\nYou tried to register an additional method with `;

      if (type) {
        msg += `type "${type.toString()}".`
      } else {
        msg += 'universal type.'
      }

      msg += '\nThere are existing registrations for that method with ';

      const conflictingRegistrations = CPt[methodName].typedRegistrations;

      if (conflictingRegistrations) {
        msg += `type ${Object.keys(conflictingRegistrations).join(', ')}.`;
      } else {
        msg += 'universal type.';
      }

      throw Error(msg);
    }
    if (!type) {
      CPt[methodName] = methods[methodName];
    } else {
      type = type.toString();
      if (!CPt.hasOwnProperty(methodName)) {
        installTypedMethod(methodName);
      }
      var registrations = CPt[methodName].typedRegistrations;
      registrations[type] = methods[methodName];
      astTypes.getSupertypeNames(type).forEach(function (name) {
        registrations[name] = false;
      });
    }
  }
}
This function adds the provided methods to the prototype of the corresponding
typed collection. If no type is passed, the methods are added to
Collection.prototype and are available for all collections.

@param {Object} methods Methods to add to the prototype
@param {Type=} type Optional type to add the methods to