/**
 * Map a nullish value as if it were non-nullish.
 *
 * The result retains either `null`, or `undefined`, or both, or neither, depending on what's inferred from the input value.
 *
 * Practically, the possible mappings are:
 *
 * ---
 *
 * `T | null | undefined` => `R | null | undefined`
 * ```ts
 * const val = 0 as number | null | undefined;
 * const res = nullishMap(val, val => `${val}`);
 * //    ^ string | null | undefined
 * ```
 *
 * ---
 *
 * `T | undefined` => `R | undefined`
 * ```ts
 * const val = 0 as number | undefined;
 * const res = nullishMap(val, val => `${val}`);
 * //    ^ string | undefined
 * ```
 *
 * ---
 *
 * `T | null` => `R | null`
 * ```ts
 * const val = 0 as number | null;
 * const res = nullishMap(val, val => `${val}`);
 * //    ^ string | null
 * ```
 *
 * ---
 *
 * `T` => `R` _(not terribly useful, but it's allowed for simplicity's sake)_
 * ```ts
 * const val = 0 as number;
 * const res = nullishMap(val, val => `${val}`);
 * //    ^ string
 * ```
 *
 */
declare function nullishMap<T, R>(value: T, mapFn: (value: NonNullable<T>) => R): NullishMap<T, R>;
/**
 * Union of `R`, and either `null`, `undefined`, or both, depending on which of the two are constituents of `T`.
 *
 * @see {@link nullishMap}
 */
type NullishMap<T, R> = T extends null ? null : T extends undefined ? undefined : R;

/**
 * Augment a value's type with `null` and `undefined`.
 *
 * Zero performance impact at runtime, as it is simply an identity function, and it most likely gets inlined.
 *
 * Useful in a few common situations:
 *
 * ---
 *
 * Making an inferred type optional at variable declaration, since something like https://github.com/microsoft/TypeScript/issues/13321 is not yet possible:
 * ```ts
 * let optional = nullishOf({ foo: 1, bar: 2, }) ?? void 0;
 * //  ^ { foo: number; bar: number; } | undefined
 * ```
 * ---
 * Safely accessing arrays without enabling `noUncheckedIndexedAccess` in `tsconfig.json`:
 * ```ts
 * const myArray = [0, , 2].map(n => Boolean(n));
 *
 * // Without `noUncheckedIndexedAccess`:
 * let element = myArray[1];
 * //  ^ `boolean`
 * //    this is incorrect, due to the empty element
 *
 * // With manual typing:
 * let maybeElement1 = myArray[1] as undefined | (typeof myArray)[number];
 * //  ^ `boolean | undefined`
 * //    correct, but a hassle to type
 *
 * // With `nullishOf`:
 * let maybeElement2 = nullishOf(myArray[1]);
 * //  ^ `boolean | null | undefined`
 * //    correct enough: it has an extraneous `null`, but that's fine in most situations
 *
 * // And if you want to narrow to either `null` or `undefined`:
 * let maybeElement3 = nullishOf(myArray[1]) ?? null;
 * //  ^ `boolean | null`
 * //    correct
 * let maybeElement4 = nullishOf(myArray[1]) ?? void 0;
 * //  ^ `boolean | undefined`
 * //    correct
 * ```
 */
declare function nullishOf<T>(value: T): T | null | undefined;

export { type NullishMap, nullishMap, nullishOf };
