or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-map-obj

Map object keys and values into a new object

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/map-obj@5.0.x

To install, run

npx @tessl/cli install tessl/npm-map-obj@5.0.0

index.mddocs/

Map Object

Map Object provides a utility function for mapping object keys and values into new objects, supporting both shallow and deep transformation of nested structures. It offers a flexible mapper function that allows developers to rename keys, transform values, and selectively exclude properties using a special skip symbol, with built-in support for recursive processing of nested objects and arrays while maintaining proper circular reference handling.

Package Information

  • Package Name: map-obj
  • Package Type: npm
  • Language: JavaScript/TypeScript
  • Installation: npm install map-obj

Core Imports

import mapObject, { mapObjectSkip } from "map-obj";

For CommonJS:

const mapObject = require("map-obj");
const { mapObjectSkip } = require("map-obj");

Basic Usage

import mapObject, { mapObjectSkip } from "map-obj";

// Transform keys and values
const result = mapObject({ foo: "bar" }, (key, value) => [value, key]);
// Result: { bar: "foo" }

// Transform keys (e.g., normalize case)
const normalized = mapObject(
  { FOO: true, bAr: { bAz: true } },
  (key, value) => [key.toLowerCase(), value]
);
// Result: { foo: true, bar: { bAz: true } }

// Deep transformation
const deepNormalized = mapObject(
  { FOO: true, bAr: { bAz: true } },
  (key, value) => [key.toLowerCase(), value],
  { deep: true }
);
// Result: { foo: true, bar: { baz: true } }

// Exclude properties using skip symbol
const filtered = mapObject(
  { one: 1, two: 2 },
  (key, value) => (value === 1 ? [key, value] : mapObjectSkip)
);
// Result: { one: 1 }

Capabilities

Map Object Function

Maps object keys and values into a new object using a provided mapper function.

/**
 * Map object keys and values into a new object
 * @param source - The source object to copy properties from
 * @param mapper - A mapping function that transforms keys and values
 * @param options - Optional configuration for mapping behavior
 * @returns New object with mapped keys and values
 */
function mapObject<
  SourceObjectType extends Record<string, unknown>,
  TargetObjectType extends Record<string, any>,
  MappedObjectKeyType extends string,
  MappedObjectValueType,
>(
  source: SourceObjectType,
  mapper: Mapper<SourceObjectType, MappedObjectKeyType, MappedObjectValueType>,
  options: DeepOptions & TargetOptions<TargetObjectType>
): TargetObjectType & Record<string, unknown>;

function mapObject<
  SourceObjectType extends Record<string, unknown>,
  MappedObjectKeyType extends string,
  MappedObjectValueType,
>(
  source: SourceObjectType,
  mapper: Mapper<SourceObjectType, MappedObjectKeyType, MappedObjectValueType>,
  options: DeepOptions
): Record<string, unknown>;

function mapObject<
  SourceObjectType extends Record<string, any>,
  TargetObjectType extends Record<string, any>,
  MappedObjectKeyType extends string,
  MappedObjectValueType,
>(
  source: SourceObjectType,
  mapper: Mapper<SourceObjectType, MappedObjectKeyType, MappedObjectValueType>,
  options: TargetOptions<TargetObjectType>
): TargetObjectType & {[K in MappedObjectKeyType]: MappedObjectValueType};

function mapObject<
  SourceObjectType extends Record<string, any>,
  MappedObjectKeyType extends string,
  MappedObjectValueType,
>(
  source: SourceObjectType,
  mapper: Mapper<SourceObjectType, MappedObjectKeyType, MappedObjectValueType>,
  options?: Options
): {[K in MappedObjectKeyType]: MappedObjectValueType};

Usage Examples:

// Key transformation
const camelCased = mapObject(
  { "first-name": "John", "last-name": "Doe" },
  (key, value) => [key.replace(/-(\w)/g, (_, char) => char.toUpperCase()), value]
);
// Result: { firstName: "John", lastName: "Doe" }

// Value transformation
const doubled = mapObject(
  { a: 1, b: 2, c: 3 },
  (key, value) => [key, value * 2]
);
// Result: { a: 2, b: 4, c: 6 }

// Using target option
const target = { existing: "value" };
const merged = mapObject(
  { new: "data" },
  (key, value) => [key, value],
  { target }
);
// Result: target object is modified and returned

Map Object Skip Symbol

Special symbol returned from a mapper function to exclude a key from the result object.

/**
 * Return this value from a mapper function to remove a key from an object
 */
const mapObjectSkip: unique symbol;

Usage Examples:

import mapObject, { mapObjectSkip } from "map-obj";

// Conditional inclusion
const adults = mapObject(
  { alice: 25, bob: 16, charlie: 30 },
  (key, value) => (value >= 18 ? [key, value] : mapObjectSkip)
);
// Result: { alice: 25, charlie: 30 }

// Property filtering based on key patterns
const publicProps = mapObject(
  { name: "John", _private: "secret", age: 30, _id: 123 },
  (key, value) => (key.startsWith("_") ? mapObjectSkip : [key, value])
);
// Result: { name: "John", age: 30 }

Types

Mapper Function Type

type Mapper<
  SourceObjectType extends Record<string, any>,
  MappedObjectKeyType extends string,
  MappedObjectValueType,
> = (
  sourceKey: keyof SourceObjectType,
  sourceValue: SourceObjectType[keyof SourceObjectType],
  source: SourceObjectType
) => [
  targetKey: MappedObjectKeyType,
  targetValue: MappedObjectValueType,
  mapperOptions?: MapperOptions,
] | typeof mapObjectSkip;

Options Interface

interface Options {
  /**
   * Recurse nested objects and objects in arrays
   * @default false
   */
  readonly deep?: boolean;

  /**
   * The target object to map properties on to
   * @default {}
   */
  readonly target?: Record<string, any>;
}

Deep Options Interface

interface DeepOptions extends Options {
  readonly deep: true;
}

Target Options Interface

interface TargetOptions<TargetObjectType extends Record<string, any>> extends Options {
  readonly target: TargetObjectType;
}

Mapper Options Interface

interface MapperOptions {
  /**
   * Whether targetValue should be recursed
   * Requires deep: true
   * @default true
   */
  readonly shouldRecurse?: boolean;
}

Advanced Usage

Deep Object Mapping

const nested = {
  user: {
    profile: {
      firstName: "John",
      lastName: "Doe"
    },
    preferences: ["email", "sms"]
  }
};

const normalized = mapObject(
  nested,
  (key, value) => [key.toLowerCase(), value],
  { deep: true }
);
// All nested keys are transformed recursively

Selective Recursion Control

const data = {
  metadata: { version: "1.0", author: "John" },
  content: { title: "Example", body: "Content here" }
};

const result = mapObject(
  data,
  (key, value) => {
    if (key === "metadata") {
      // Don't recurse into metadata
      return [key, value, { shouldRecurse: false }];
    }
    return [key.toUpperCase(), value];
  },
  { deep: true }
);
// metadata object is not recursively transformed

Circular Reference Handling

const obj = { name: "test" };
obj.self = obj; // Create circular reference

const mapped = mapObject(
  obj,
  (key, value) => [key.toUpperCase(), value],
  { deep: true }
);
// Circular references are handled automatically using WeakMap tracking

Error Handling

The mapObject function validates its input and throws TypeError in the following cases:

  • When the first argument is not an object: TypeError: Expected an object, got \value` (type)`
  • When the first argument is an array: TypeError: Expected an object, got an array
try {
  mapObject(null, (k, v) => [k, v]);
} catch (error) {
  console.log(error.message); // "Expected an object, got `null` (object)"
}

try {
  mapObject([1, 2, 3], (k, v) => [k, v]);
} catch (error) {
  console.log(error.message); // "Expected an object, got an array"
}