iterableSearchParamsToString = function(iterable) {
  // Some characters are not form-encoded properly by encodeURIComponent, so we
  // enumerate their replacements here for use later.
  const encode = (s) => {
    // Form encoding is defined [in the spec][1] but there are some values that
    // are not encoded the right way by encodeURIComponent. Thus, we replace
    // their representation in the resulting encoded string with their actual
    // encoding.
    // [1]: https://url.spec.whatwg.org/#urlencoded-serializing
    return encodeURIComponent(s).replace(/[!()~']|(%20)/g, (c) => {
      return {
        '!': '%21',
        '(': '%28',
        ')': '%29',
        '%20': '+',
        '\'': '%27',
        '~': '%7E',
      }[c];
    });
  };
  return Array
      .from(
          iterable,
          (keyValuePair) =>
              encode(keyValuePair[0]) + '=' + encode(keyValuePair[1]))
      .join('&');
}
@param {!Iterable<!Array<string>>} iterable The iterable which acts like a
    URLSearchParams object (each iteration returns another key and value).
    Note that both keys and values must NOT be already URL encoded.
@return {string} The serialized SearchParams, with all keys and values
    correctly encoded.