import type { AnyObject, KeyValueTuple, MutateOptions, ObjectMapper, ObjectPredicate, RequiredProp, Reviver, StringMap, ValueOf } from '../types.js';
import { SKIP } from '../types.js';
/**
 * Returns clone of `obj` with only `props` preserved.
 * Opposite of Omit.
 */
export declare function _pick<T extends AnyObject, K extends keyof T>(obj: T, props: readonly K[], opt?: MutateOptions): T;
/**
 * Sets all properties of an object except passed ones to `undefined`.
 * This is a more performant alternative to `_pick` that does picking/deleting.
 */
export declare function _pickWithUndefined<T extends AnyObject, K extends keyof T>(obj: T, props: readonly K[], opt?: MutateOptions): T;
/**
 * Returns clone of `obj` with `props` omitted.
 * Opposite of Pick.
 */
export declare function _omit<T extends AnyObject, K extends keyof T>(obj: T, props: readonly K[], opt?: MutateOptions): T;
/**
 * Sets all passed properties of an object to `undefined`.
 * This is a more performant alternative to `_omit` that does picking/deleting.
 */
export declare function _omitWithUndefined<T extends AnyObject, K extends keyof T>(obj: T, props: readonly K[], opt?: MutateOptions): T;
/**
 * Returns object with filtered keys from `props` array.
 * E.g:
 * _mask({...}, [
 *  'account.id',
 *  'account.updated',
 * ])
 */
export declare function _mask<T extends AnyObject>(obj: T, props: string[], opt?: MutateOptions): T;
/**
 * Removes "falsy" values from the object.
 */
export declare function _filterFalsyValues<T extends AnyObject>(obj: T, opt?: MutateOptions): T;
/**
 * Removes values from the object that are `null` or `undefined`.
 */
export declare function _filterNullishValues<T extends AnyObject>(obj: T, opt?: MutateOptions): T;
/**
 * Removes values from the object that are `undefined`.
 * Only `undefined` values are removed. `null` values are kept!
 */
export declare function _filterUndefinedValues<T extends AnyObject>(obj: T, opt?: MutateOptions): T;
export declare function _filterEmptyArrays<T extends AnyObject>(obj: T, opt?: MutateOptions): T;
/**
 * Returns clone of `obj` without properties that does not pass `predicate`.
 * Allows filtering by both key and value.
 */
export declare function _filterObject<T extends AnyObject>(obj: T, predicate: ObjectPredicate<T>, opt?: MutateOptions): T;
/**
 * var users = {
 *  'fred':    { 'user': 'fred',    'age': 40 },
 *  'pebbles': { 'user': 'pebbles', 'age': 1 }
 * }
 *
 * _mapValues(users, (_key, value) => value.age)
 * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
 *
 * To skip some key-value pairs - use _mapObject instead.
 */
export declare function _mapValues<OUT = unknown, IN extends AnyObject = AnyObject>(obj: IN, mapper: ObjectMapper<IN, any>, opt?: MutateOptions): OUT;
/**
 * _.mapKeys({ 'a': 1, 'b': 2 }, (key, value) => key + value)
 * // => { 'a1': 1, 'b2': 2 }
 *
 * Does not support `mutate` flag.
 *
 * To skip some key-value pairs - use _mapObject instead.
 */
export declare function _mapKeys<T extends AnyObject>(obj: T, mapper: ObjectMapper<T, string>): T;
/**
 * Maps object through predicate - a function that receives (k, v, obj)
 * k - key
 * v - value
 * obj - whole object
 *
 * Order of arguments in the predicate is different form _mapValues / _mapKeys!
 *
 * Predicate should return a _tuple_ [0, 1], where:
 * 0 - key of returned object (string)
 * 1 - value of returned object (any)
 *
 * If predicate returns SKIP symbol - such key/value pair is ignored (filtered out).
 *
 * Non-string keys are passed via String(...)
 */
export declare function _mapObject<OUT = unknown, IN extends AnyObject = AnyObject>(obj: IN, mapper: ObjectMapper<IN, KeyValueTuple<string, any> | typeof SKIP>): OUT;
export declare function _findKeyByValue<T extends AnyObject>(obj: T, v: ValueOf<T>): keyof T | undefined;
/**
 * Returns the first key of a non-empty object.
 * Throws if the object is empty.
 *
 * Performance-optimised: uses `for...in` with an early return to avoid
 * allocating the full `Object.keys(obj)` array. The `Object.hasOwn` filter
 * matches `Object.keys()` semantics (own enumerable string keys only) and
 * satisfies the `guard-for-in` lint rule; cost is a single check before
 * the early return. Iteration order matches `Object.keys()` for plain
 * objects (integer-like keys ascending first, then string keys in
 * insertion order).
 */
export declare function _firstKey<T extends AnyObject>(obj: T): keyof T;
/**
 * Returns the first key of the object (or undefined if the object is empty).
 * See `_firstKey` for the iteration-order contract.
 */
export declare function _firstKeyOrUndefined<T extends AnyObject>(obj: T): keyof T | undefined;
/**
 * Returns the first value of a non-empty object.
 * Throws if the object is empty.
 * See `_firstKey` for the iteration-order contract.
 */
export declare function _firstValue<T extends AnyObject>(obj: T): ValueOf<T>;
/**
 * Returns the first value of the object (or undefined if the object is empty).
 * See `_firstKey` for the iteration-order contract.
 */
export declare function _firstValueOrUndefined<T extends AnyObject>(obj: T): ValueOf<T> | undefined;
/**
 * Returns the first [key, value] tuple of a non-empty object.
 * Throws if the object is empty.
 * See `_firstKey` for the iteration-order contract.
 */
export declare function _firstEntry<T extends AnyObject>(obj: T): [keyof T, ValueOf<T>];
/**
 * Returns the first [key, value] tuple of the object (or undefined if the object is empty).
 * See `_firstKey` for the iteration-order contract.
 */
export declare function _firstEntryOrUndefined<T extends AnyObject>(obj: T): [keyof T, ValueOf<T>] | undefined;
export declare function _objectNullValuesToUndefined<T extends AnyObject>(obj: T, opt?: MutateOptions): T;
/**
 * Deep copy object (by json parse/stringify, since it has unbeatable performance+simplicity combo).
 */
export declare function _deepCopy<T>(o: T, reviver?: Reviver): T;
/**
 * Performance-optimized implementation of merging two objects
 * without mutating any of them.
 * (if you are allowed to mutate - there can be a faster implementation).
 *
 * Gives ~40% speedup with map sizes between 10 and 100k items,
 * compared to {...obj1, ...obj2} or Object.assign({}, obj1, obj2).
 *
 * Only use it in hot paths that are known to be performance bottlenecks,
 * otherwise it's not worth it (use normal object spread then).
 */
export declare function _mergeObjects<T>(obj1: StringMap<T>, obj2: StringMap<T>): StringMap<T>;
/**
 * Returns `undefined` if it's empty (according to `_isEmpty()` specification),
 * otherwise returns the original object.
 */
export declare function _undefinedIfEmpty<T>(obj: T | undefined): T | undefined;
/**
 * Filters the object by removing all key-value pairs where Value is Empty (according to _isEmpty() specification).
 */
export declare function _filterEmptyValues<T extends AnyObject>(obj: T, opt?: MutateOptions): T;
/**
 * Recursively merges own and inherited enumerable properties of source
 * objects into the destination object, skipping source properties that resolve
 * to `undefined`. Array and plain object properties are merged recursively.
 * Other objects and value types are overridden by assignment. Source objects
 * are applied from left to right. Subsequent sources overwrite property
 * assignments of previous sources.
 *
 * Works as "recursive Object.assign".
 *
 * **Note:** This method mutates `object`.
 *
 * @param target The destination object.
 * @param sources The source objects.
 * @returns Returns `object`.
 * @example
 *
 * var users = {
 *   'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
 * };
 *
 * var ages = {
 *   'data': [{ 'age': 36 }, { 'age': 40 }]
 * };
 *
 * _.merge(users, ages);
 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
 *
 * Based on: https://gist.github.com/Salakar/1d7137de9cb8b704e48a
 */
export declare function _merge<T extends AnyObject>(target: T, ...sources: any[]): T;
/**
 * Trims all object VALUES deeply.
 * Doesn't touch object KEYS.
 * Mutates.
 */
export declare function _deepTrim<T extends AnyObject | string>(o: T): T;
export declare function _unset<T extends AnyObject>(obj: T, prop: string): void;
export declare function _invert<T extends AnyObject>(o: T): {
    [k in ValueOf<T>]: keyof T | undefined;
};
export declare function _invertMap<K, V>(m: ReadonlyMap<K, V>): Map<V, K>;
/**
 * Gets the property value at path of object.
 *
 * @example
 * const obj = {a: 'a', b: 'b', c: { cc: 'cc' }}
 * _get(obj, 'a') // 'a'
 * _get(obj, 'c.cc') // 'cc'
 * _get(obj, 'c[cc]') // 'cc'
 * _get(obj, 'unknown.path') // undefined
 */
export declare function _get<T extends AnyObject>(obj?: T, path?: string): unknown;
type Many<T> = T | readonly T[];
type PropertyPath = Many<PropertyKey>;
/**
 * Sets the value at path of object. If a portion of path doesn’t exist it’s created. Arrays are created for
 * missing index properties while objects are created for all other missing properties.
 *
 * @param obj The object to modify.
 * @param path The path of the property to set.
 * @param value The value to set.
 * @returns Returns object.
 *
 * Based on: https://stackoverflow.com/a/54733755/4919972
 */
export declare function _set<T extends AnyObject>(obj: T, path: PropertyPath, value: any): T;
/**
 * Checks if `path` is a direct property of `object` (not null, not undefined).
 *
 * @param obj The object to query.
 * @param path The path to check.
 * @returns Returns `true` if `path` exists, else `false`.
 * @example
 *
 * var object = { 'a': { 'b': { 'c': 3 } } };
 * var other = _.create({ 'a': _.create({ 'b': _.create({ 'c': 3 }) }) });
 *
 * _.has(object, 'a');
 * // => true
 *
 * _.has(object, 'a.b.c');
 * // => true
 *
 * _.has(object, ['a', 'b', 'c']);
 * // => true
 *
 * _.has(other, 'a');
 * // => false
 */
export declare function _has<T extends AnyObject>(obj: T, path: string): boolean;
/**
 * Does Object.freeze recursively for given object.
 *
 * Based on: https://github.com/substack/deep-freeze/blob/master/index.js
 */
export declare function _deepFreeze(o: any): void;
/**
 * let target: T = { a: 'a', n: 1}
 * let source: T = { a: 'a2', b: 'b' }
 *
 * _objectAssignExact(target, source)
 *
 * Does the same as `target = source`,
 * except that it mutates the target to make it exactly the same as source,
 * while keeping the reference to the same object.
 *
 * This way it can "propagate deletions".
 * E.g source doesn't have the `n` property, so it'll be deleted from target.
 * With normal Object.assign - it'll override the keys that `source` has, but not the
 * "missing/deleted keys".
 *
 * To make mutation extra clear - function returns void (unlike Object.assign).
 */
export declare function _objectAssignExact<T extends AnyObject>(target: T, source: T): void;
/**
 * type MyObj = { a?: string, b?: string }
 *
 * const collection: MyObj[] = [...]
 *
 * const collectionA = collection.filter(_hasProp('a'))
 * --> collectionA is now RequiredProp<MyObj, 'a'>[], i.e. { a: string, b?: string }[]
 */
export declare function _hasProp<T, Prop extends keyof T>(prop: Prop): (object: T) => object is RequiredProp<T, Prop>;
export {};
