/**
 * @template {boolean} [Gapless=false]
 * @typedef Options
 *   Configuration (optional).
 * @property {Gapless|undefined} [gapless=false]
 *   Whether to filter out `null` and `undefined` results
 * @property {string|undefined} [key]
 *   If a key is given, and an object supplied to the wrapped `fn`, values at
 *   that object’s `key` field are mapped and the object, instead of the
 *   values, is given to `fn` as a last parameter.
 *   If a key is given and an array is passed to the wrapped `fn`, no value is
 *   given to `fn` as a last parameter.
 */
/**
 * Functional map with sugar (functional, as values are provided as a parameter,
 * instead of context object).
 *
 * Wraps the supplied `fn`, which handles one value, so that it accepts multiple
 * values, calling `fn` for each and returning all results.
 *
 * If `options` is a string, it’s treated as `{key: options}`.
 *
 * @template {unknown} [ChildValue=unknown]
 * @template {unknown} [ParentValue=unknown]
 * @template {unknown} [ReturnValue=unknown]
 * @template {boolean} [Gapless=false]
 * @param {(value: ChildValue, parent: ParentValue) => ReturnValue} fn
 * @param {string|Options<Gapless>|undefined} [options]
 */
export function mapz<
  ChildValue extends unknown = unknown,
  ParentValue extends unknown = unknown,
  ReturnValue extends unknown = unknown,
  Gapless extends boolean = false
>(
  fn: (value: ChildValue, parent: ParentValue) => ReturnValue,
  options?: string | Options<Gapless> | undefined
): (
  this: unknown,
  values: ParentValue | ChildValue[]
) => (Gapless extends true ? NonNullable<ReturnValue> : ReturnValue)[]
/**
 * Configuration (optional).
 */
export type Options<Gapless extends boolean = false> = {
  /**
   * Whether to filter out `null` and `undefined` results
   */
  gapless?: Gapless | undefined
  /**
   * If a key is given, and an object supplied to the wrapped `fn`, values at
   * that object’s `key` field are mapped and the object, instead of the
   * values, is given to `fn` as a last parameter.
   * If a key is given and an array is passed to the wrapped `fn`, no value is
   * given to `fn` as a last parameter.
   */
  key?: string | undefined
}
