Skip to content

Category: object Since: 1.0.0 Tags: object, nested, path, safe-access, typed, dot-notation

get

Safely gets a nested value from a plain object using a dot-separated path with full TypeScript type safety.

Usage

ts
import { get } from "@petr-ptacek/js-core";

const user = {
  profile: {
    name: "John",
    address: {
      city: "Prague",
    },
  },
};

const name = get(user, "profile.name");
console.log(name); // "John"

const city = get(user, "profile.address.city");
console.log(city); // "Prague"

const age = get(user, "profile.age" as any, 0);
console.log(age); // 0

Why This Utility Exists

Direct property access can throw runtime errors when intermediate properties are null or undefined. Optional chaining lacks type safety for deep paths and always returns potentially any types. This utility provides safe access with compile-time path validation and full type inference.

Signature

ts
// Without default value
function get<T extends object, P extends DotPathKeys<T>>(obj: T, path: P): DotPathValue<T, P> | undefined;

// With default value
function get<T extends object, P extends DotPathKeys<T>, D>(
  obj: T,
  path: P,
  defaultValue: D
): Exclude<DotPathValue<T, P>, undefined> | D;

Parameters

  • obj (T extends object): The plain object to access.
  • path (P extends DotPathKeys<T>): The dot-separated path string.
  • defaultValue (D, optional): Value to return if the path resolves to undefined.

Type Parameters

  • <T extends object>: The type of the input object.
  • <P extends DotPathKeys<T>>: The valid path type derived from the object structure.
  • <D>: The type of the default value (when provided).

Return Type

Returns the value at the specified path, or undefined if the path doesn't exist. When a default value is provided, returns the default value instead of undefined for missing paths. The return type is automatically inferred based on the path and object structure.

Design Notes

The utility uses DotPathKeys<T> and DotPathValue<T, P> from the type category to validate paths at compile time. Only valid paths that exist in the plain object structure are accepted.

Only plain objects are traversed. Arrays, Date, Map, Set, functions, and other non-plain-object values are treated as leaves — traversal stops and undefined is returned when a path segment reaches such a value.

When To Use

Use get when you need:

  • safe deep property access without runtime errors
  • type-safe path strings validated at compile time
  • fallback values for missing properties

When Not To Use

Avoid when:

  • shallow access where optional chaining (obj?.prop) is sufficient
  • the path goes through an array or non-plain-object value — those are not traversed
  • dynamic paths that cannot be known at compile time
  • performance-critical code where direct access is faster

Summary

get provides safe and type-safe access to nested plain object properties with compile-time path validation and graceful handling of missing values.

Snippets

api-response.ts

ts
import { get } from "@petr-ptacek/js-core";

const apiResponse = {
  data: {
    user: {
      id: 1,
      profile: {
        email: "alice@example.com",
        preferences: { theme: "dark" },
      },
    },
    meta: {
      pagination: {
        total: 42,
        page: 1,
      },
    },
  },
};

// Safely access nested API data
const userEmail = get(apiResponse, "data.user.profile.email");
console.log(userEmail); // "alice@example.com"

const userTheme = get(apiResponse, "data.user.profile.preferences.theme", "light");
console.log(userTheme); // "dark"

// Access meta information with defaults
const total = get(apiResponse, "data.meta.pagination.total", 0);
console.log(total); // 42

basic.ts

ts
import { get } from "@petr-ptacek/js-core";

const user = {
  profile: {
    name: "John",
    age: 30,
    address: {
      city: "Prague",
      zip: "110 00",
    },
  },
};

// Get nested object property
const name = get(user, "profile.name");
console.log(name); // "John"

// Get deeply nested value
const city = get(user, "profile.address.city");
console.log(city); // "Prague"

// Get with default value (existing property)
const age = get(user, "profile.age", 25);
console.log(age); // 30

// Get with default value (missing property)
const nickname = get(user, "profile.nickname" as any, "anonymous");
console.log(nickname); // "anonymous"

config.ts

ts
import { get } from "@petr-ptacek/js-core";

const config = {
  server: {
    port: 3000,
    host: "localhost",
    ssl: true,
    database: {
      host: "db.example.com",
      credentials: {
        username: "admin",
        password: "secret123",
      },
    },
  },
};

// Access configuration values with sensible defaults
const port = get(config, "server.port", 8080);
const host = get(config, "server.host", "0.0.0.0");
const sslEnabled = get(config, "server.ssl", false);

// Access deeply nested configuration
const dbHost = get(config, "server.database.host", "localhost");
const dbUser = get(config, "server.database.credentials.username", "user");

console.log({
  port,
  host,
  sslEnabled,
  dbHost,
  dbUser,
});