Skip to content
VersionSize

get

The get utility safely retrieves a nested value from an object using a dot-notation path string. It prevents runtime errors when accessing properties of undefined or null intermediate objects and supports an optional default value.

Source Code

View Source Code
ts
import type { Obj } from '../types';

import { assert } from '../function/assert';
import { isNil } from '../typed/isNil';
import { IS_OBJECT_ERROR_MSG, isObject } from '../typed/isObject';

type PathValue<T, P extends string> = P extends `${infer Key}.${infer Rest}`
  ? Key extends keyof T
    ? PathValue<T[Key], Rest>
    : undefined
  : P extends keyof T
    ? T[P]
    : undefined;

// #region PathOptions
type PathOptions = {
  throwOnMissing?: boolean;
};
// #endregion PathOptions

/**
 * Retrieves the value at a given path of the object. If the value is undefined, the default value is returned.
 *
 * @example
 * ```ts
 * const obj = { a: { b: { c: 3 } }, d: [1, 2, 3] };
 *
 * getValue(obj, 'a.b.c'); // 3
 * getValue(obj, 'a.b.d', 'default'); // 'default'
 * getValue(obj, 'd[1]'); // 2
 * getValue(obj, 'e.f.g', 'default', { throwOnMissing: true }); // throws Error
 * ```
 *
 * @template T - The type of the object to query.
 * @template P - The type of the path string.
 * @param item - The object to query.
 * @param path - The dot-separated path of the property to get.
 * @param [defaultValue] - The value returned for undefined resolved values.
 * @param [options] - Additional options for value retrieval.
 *
 * @returns The resolved value.
 *
 * @throws If throwOnMissing is true and the path doesn't exist.
 */
export function get<T extends Obj, P extends string>(
  item: T,
  path: P,
  defaultValue?: unknown,
  options: PathOptions = {},
): PathValue<T, P> | undefined {
  assert(isObject(item), IS_OBJECT_ERROR_MSG, { args: { item }, type: TypeError });

  const { throwOnMissing = false } = options;

  const fragments = path.split(/[.[\]]+/).filter(Boolean);
  let current: any = item;

  for (const fragment of fragments) {
    if (isNil(current) || typeof current !== 'object') {
      if (throwOnMissing) throw new Error(`Cannot read property '${fragment}' of ${current}`);

      return defaultValue as PathValue<T, P>;
    }

    current = current[fragment];

    if (current === undefined) {
      if (throwOnMissing) throw new Error(`Property '${fragment}' does not exist`);

      return defaultValue as PathValue<T, P>;
    }
  }

  return current as PathValue<T, P>;
}

Features

  • Isomorphic: Works in both Browser and Node.js.
  • Safe Access: Never throws if a parent is null or undefined (unless throwOnMissing is set).
  • Dot & Bracket Notation: Supports 'a.b.c' and 'a[0].b' path formats.
  • Default Value: Provide a fallback value for missing or undefined paths.
  • Type-safe: Generic return type with full TypeScript inference.

API

Type Definitions
ts
type PathOptions = {
  throwOnMissing?: boolean;
};
ts
function get<T extends object, P extends string>(
  item: T,
  path: P,
  defaultValue?: unknown,
  options?: PathOptions,
): unknown;

Parameters

  • item: The object to query.
  • path: The path to the desired property as a dot-separated (or bracket-notation) string.
  • defaultValue: Optional. A value returned when the path is missing or resolves to undefined.
  • options: Optional configuration:
    • throwOnMissing: If true, throws an Error instead of returning the default value.

Returns

The value at the path, the defaultValue, or undefined.

Examples

Basic Nested Access

ts
import { get } from '@vielzeug/toolkit';

const config = {
  api: {
    endpoints: {
      login: '/api/v1/login',
    },
  },
};

get(config, 'api.endpoints.login'); // '/api/v1/login'
get(config, 'api.version'); // undefined
get(config, 'api.version', 'v1'); // 'v1' (default value)

Array Index Access

ts
import { get } from '@vielzeug/toolkit';

const data = {
  users: [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' },
  ],
};

get(data, 'users[0].name'); // 'Alice'
get(data, 'users[1].id'); // 2

Throwing on Missing Paths

ts
import { get } from '@vielzeug/toolkit';

const obj = { a: { b: 1 } };

// Throws an error instead of returning the default value
get(obj, 'e.f.g', undefined, { throwOnMissing: true }); // throws Error

Implementation Notes

  • Bracket notation ([0]) is parsed and treated as a key automatically.
  • Returns defaultValue only when the resolved value is undefined; null is returned as-is.

See Also

  • seek: Recursively search object values by similarity score.
  • merge: Combine multiple objects together.