or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

array-operations.mdfunction-utilities.mdindex.mdmath-operations.mdobject-operations.mdpromise-utilities.mdstring-operations.mdtime-performance.mdtype-guards.md
tile.json

object-operations.mddocs/

Object Operations

Object manipulation and transformation utilities providing type-safe operations for mapping, merging, filtering, and analyzing object structures.

Capabilities

Object Transformation

Transform object key-value pairs with type-safe operations.

/**
 * Map key/value pairs for an object, and construct a new one
 * @param obj - Object to transform
 * @param fn - Transformation function returning new [key, value] pair or undefined to omit
 * @returns New object with transformed key-value pairs
 */
function objectMap<K extends string, V, NK extends string | number | symbol = K, NV = V>(
  obj: Record<K, V>, 
  fn: (key: K, value: V) => [NK, NV] | undefined
): Record<NK, NV>;

Usage Examples:

import { objectMap } from "@antfu/utils";

// Transform keys and values
const transformed = objectMap(
  { a: 1, b: 2 }, 
  (k, v) => [k.toUpperCase(), v.toString()]
);
// { A: '1', B: '2' }

// Swap key/value
const swapped = objectMap({ a: 1, b: 2 }, (k, v) => [v, k]);
// { 1: 'a', 2: 'b' }

// Filter keys
const filtered = objectMap(
  { a: 1, b: 2, c: 3 }, 
  (k, v) => k === 'a' ? undefined : [k, v]
);
// { b: 2, c: 3 }

Object Type Guards & Key Operations

Type-safe object key checking and manipulation.

/**
 * Type guard for any key, `k`.
 * Marks `k` as a key of `T` if `k` is in `obj`.
 * @param obj - Object to query for key `k`
 * @param k - Key to check existence in `obj`
 * @returns True if key exists in object
 */
function isKeyOf<T extends object>(obj: T, k: keyof any): k is keyof T;

/**
 * Strict typed `Object.keys`
 * @param obj - Object to get keys from
 * @returns Array of object keys with proper typing
 */
function objectKeys<T extends object>(obj: T): Array<`${keyof T & (string | number | boolean | null | undefined)}`>;

/**
 * Strict typed `Object.entries`
 * @param obj - Object to get entries from
 * @returns Array of [key, value] pairs with proper typing
 */
function objectEntries<T extends object>(obj: T): Array<[keyof T, T[keyof T]]>;

Usage Examples:

import { isKeyOf, objectKeys, objectEntries } from "@antfu/utils";

const user = { name: "Alice", age: 30, active: true };

// Safe key checking
function getValue(key: string) {
  if (isKeyOf(user, key)) {
    return user[key]; // TypeScript knows key is valid
  }
  return undefined;
}

// Typed object iteration
const keys = objectKeys(user); // ("name" | "age" | "active")[]
const entries = objectEntries(user); // ["name" | "age" | "active", string | number | boolean][]

// Process all entries safely
entries.forEach(([key, value]) => {
  console.log(`${key}: ${value}`);
});

Deep Merging

Advanced object merging with deep property merging capabilities.

/**
 * Deep merge objects
 * The first argument is the target object, the rest are the sources.
 * The target object will be mutated and returned.
 * @param target - Target object (will be mutated)
 * @param sources - Source objects to merge
 * @returns The merged target object
 */
function deepMerge<T extends object = object, S extends object = T>(target: T, ...sources: S[]): DeepMerge<T, S>;

/**
 * Deep merge with array merging
 * Differs from `deepMerge` in that it merges arrays instead of overriding them.
 * The first argument is the target object, the rest are the sources.
 * The target object will be mutated and returned.
 * @param target - Target object (will be mutated)
 * @param sources - Source objects to merge
 * @returns The merged target object
 */
function deepMergeWithArray<T extends object = object, S extends object = T>(target: T, ...sources: S[]): DeepMerge<T, S>;

Usage Examples:

import { deepMerge, deepMergeWithArray } from "@antfu/utils";

// Basic deep merge
const target = { a: 1, nested: { x: 10 } };
const source = { b: 2, nested: { y: 20 } };
const merged = deepMerge(target, source);
// { a: 1, b: 2, nested: { x: 10, y: 20 } }

// Array merging behavior difference
const withArrays = { items: [1, 2], data: { count: 1 } };
const moreArrays = { items: [3, 4], data: { total: 10 } };

// Standard deep merge (arrays are replaced)
const standardMerge = deepMerge({ ...withArrays }, moreArrays);
// { items: [3, 4], data: { count: 1, total: 10 } }

// Array-merging deep merge (arrays are combined)
const arrayMerge = deepMergeWithArray({ ...withArrays }, moreArrays);
// { items: [1, 2, 3, 4], data: { count: 1, total: 10 } }

Object Filtering & Selection

Select and filter object properties with type safety.

/**
 * Create a new subset object by giving keys
 * @param obj - Source object
 * @param keys - Keys to pick from the object
 * @param omitUndefined - Whether to omit undefined values
 * @returns New object with only the specified keys
 */
function objectPick<O extends object, T extends keyof O>(
  obj: O, 
  keys: T[], 
  omitUndefined?: boolean
): Pick<O, T>;

/**
 * Clear undefined fields from an object. It mutates the object
 * @param obj - Object to clean (mutated)
 * @returns The cleaned object
 */
function clearUndefined<T extends object>(obj: T): T;

Usage Examples:

import { objectPick, clearUndefined } from "@antfu/utils";

const user = {
  id: 1,
  name: "Alice",
  email: "alice@example.com",
  age: 30,
  password: "secret",
  settings: undefined
};

// Pick specific properties
const publicUser = objectPick(user, ["id", "name", "email"]);
// { id: 1, name: "Alice", email: "alice@example.com" }

// Pick with undefined handling
const withUndefined = objectPick(user, ["name", "settings"]);
// { name: "Alice", settings: undefined }

const withoutUndefined = objectPick(user, ["name", "settings"], true);
// { name: "Alice" }

// Clean undefined values (mutates original)
const messy = { a: 1, b: undefined, c: "hello", d: undefined };
clearUndefined(messy); // messy is now { a: 1, c: "hello" }

Object Property Checking

Safe property existence checking utilities.

/**
 * Determines whether an object has a property with the specified name
 * Safe alternative to obj.hasOwnProperty(prop)
 * @param obj - Object to check
 * @param v - Property key to check
 * @returns True if object has the specified property
 */
function hasOwnProperty<T>(obj: T, v: PropertyKey): boolean;

Usage Examples:

import { hasOwnProperty } from "@antfu/utils";

const obj = { a: 1, b: 2 };
const nullObj = null;

// Safe property checking
if (hasOwnProperty(obj, 'a')) {
  console.log(obj.a); // Safe to access
}

// Works safely with null/undefined
if (hasOwnProperty(nullObj, 'a')) { // false, no error
  console.log("Won't execute");
}

// Check for inherited vs own properties
const child = Object.create({ inherited: true });
child.own = 'value';

console.log(hasOwnProperty(child, 'own')); // true
console.log(hasOwnProperty(child, 'inherited')); // false

Object Identity

Generate unique identifiers for objects.

/**
 * Get an object's unique identifier
 * Same object will always return the same id
 * Expect argument to be a non-primitive object/array. Primitive values will be returned as is.
 * @param obj - Object to get identifier for
 * @returns Unique string identifier for the object
 */
function objectId(obj: WeakKey): string;

Usage Examples:

import { objectId } from "@antfu/utils";

const obj1 = { name: "Alice" };
const obj2 = { name: "Alice" }; // Different object, same content
const obj3 = obj1; // Same object reference

// Generate unique IDs
const id1 = objectId(obj1); // e.g., "abc123def"
const id2 = objectId(obj2); // e.g., "xyz789ghi" (different from id1)
const id3 = objectId(obj3); // Same as id1 (same object)

// Primitive values are returned as-is
const primitiveId = objectId("hello" as any); // "hello"

// Useful for object tracking and caching
const cache = new Map();
function expensiveOperation(obj: object) {
  const id = objectId(obj);
  if (cache.has(id)) {
    return cache.get(id);
  }
  const result = /* expensive computation */;
  cache.set(id, result);
  return result;
}