Skip to content

Object Utilities

Helpers for picking, omitting and cleaning object keys, reading and writing nested paths, indexing lists into records, and converting objects to FormData.

import {
  omit,
  pick,
  omitUndefined,
  nestedGet,
  nestedSet,
  toRecord,
  asFormData,
} from '@msflib/typescript';

Table of Contents


omit

omit<T extends object, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>;

Returns a shallow copy of obj without keys. The input is not mutated.

import { omit } from '@msflib/typescript';

const user = { id: 1, name: "Alice", password: "secret" };
const safeUser = omit(user, ["password"]);

console.log(safeUser);
// { id: 1, name: "Alice" }

pick

pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;

Returns a new object containing only keys.

import { pick } from '@msflib/typescript';

const user = { id: 1, name: 'Alice', email: 'alice@example.com' };
const picked = pick(user, ['id', 'email']);

console.log(picked);
// { id: 1, email: "alice@example.com" }

omitUndefined

omitUndefined<T extends object>(obj: T): Partial<T>;

Returns a shallow copy without keys whose value is undefined or null. Falsy values like 0, '' and false are kept. Handy for cleaning optional filters before sending them.

import { omitUndefined } from '@msflib/typescript';

omitUndefined({ a: 1, b: undefined, c: null, d: 0, e: '' });
// { a: 1, d: 0, e: '' }

nestedGet

nestedGet<T extends object>(obj: T, key: string): any;

Reads a dot-separated path. Returns undefined if any segment is missing (never throws).

import { nestedGet } from '@msflib/typescript';

const config = { db: { primary: { host: 'localhost' } } };

nestedGet(config, 'db.primary.host'); // "localhost"
nestedGet(config, 'db.replica.host'); // undefined

nestedSet

nestedSet<T extends object>(obj: T, path: string, value: any): void;

Writes value at a dot-separated path, mutating obj in place. Missing (or falsy) intermediate segments are created as {}. Throws a TypeError if an intermediate segment is a non-object truthy value (e.g. a number).

import { nestedSet } from '@msflib/typescript';

const form = {};
nestedSet(form, 'address.city', 'Lagos');

console.log(form);
// { address: { city: "Lagos" } }

toRecord

toRecord<T extends Record<string, any>>(list: T[], key?: keyof T): Record<string, T>;

Indexes a list by key (default 'id'). Keys are converted with String(). If two items share a key, the later one wins. Throws Error('Missing "<key>" on one or more items.') if any item's key is null or undefined.

import { toRecord } from '@msflib/typescript';

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

const byId = toRecord(users);
console.log(byId);
// { "1": { id: 1, name: 'Alice' }, "2": { id: 2, name: 'Bob' } }

const bySlug = toRecord(
  users.map((user) => ({ slug: user.name.toLowerCase(), ...user })),
  'slug',
);
console.log(bySlug);
// { alice: { slug: 'alice', id: 1, name: 'Alice' }, bob: { slug: 'bob', id: 2, name: 'Bob' } }

asFormData

asFormData(object: Record<string, any>): FormData;

Converts a flat object to FormData, one top-level key at a time:

Value Appended as
File The file
Array One entry per item, under the same key (items appended as-is)
Other object (including Blob, Date) JSON.stringify(value)
null / undefined Skipped
Anything else (string, number, boolean) String(value)
import { asFormData } from '@msflib/typescript';

const file = new File([''], 'avatar.png', { type: 'image/png' });
const user = {
  name: 'Alice',
  roles: ['admin', 'editor'],
  profile: { isVerified: true },
  avatar: file,
};

const formData = asFormData(user);

// To inspect the FormData entries:
for (const [key, value] of formData.entries()) {
  console.log(`${key}:`, value);
}

// Console Output:
// name: Alice
// roles: admin
// roles: editor
// profile: {"isVerified":true}
// avatar: [File object]

Limitations

  • Objects inside arrays are not stringified - [{ x: 1 }] is sent as "[object Object]".
  • A plain Blob that is not a File is JSON-stringified to "{}". Wrap it in a File first.
  • Requires a global File constructor: any modern browser, or Node 20+ (in Node 18 asFormData throws a ReferenceError).

See also: HTTP client · Function utilities · String utilities