UNPKG

@tienedev/datype

Version:

Modern TypeScript utility library with pragmatic typing and zero dependencies

88 lines (85 loc) 2.6 kB
'use strict'; /** * Immutably sets a nested property value in an object using dot notation. * Returns a new object with the specified property set to the new value. * * @template T - The type of the object * @param obj - The object to set the value in * @param path - The property path as a string (supports dot notation) * @param value - The value to set * @returns A new object with the property set to the new value * * @example * ```typescript * import { set } from 'datype'; * * const user = { * profile: { * name: 'John', * contact: { * email: 'john@example.com' * } * }, * preferences: ['dark-mode', 'notifications'] * }; * * // Basic usage * const updated1 = set(user, 'profile.name', 'Jane'); * // user.profile.name is still 'John' * // updated1.profile.name is 'Jane' * * // Deep nesting * const updated2 = set(user, 'profile.contact.email', 'jane@example.com'); * // Original user.profile.contact.email is unchanged * // updated2.profile.contact.email is 'jane@example.com' * * // Array modification * const updated3 = set(user, 'preferences.0', 'light-mode'); * // updated3.preferences[0] is 'light-mode' * * // Creating new nested paths * const updated4 = set(user, 'profile.contact.phone', '123-456-7890'); * // Creates the phone property in contact * * // Complex objects * const config = { * app: { * features: { * auth: { enabled: true } * } * } * }; * * const newConfig = set(config, 'app.features.payments.enabled', true); * // Creates the payments object with enabled: true * ``` */ function set(obj, path, value) { if (obj === null || obj === undefined) { throw new TypeError('Cannot set property on null or undefined'); } if (!path || typeof path !== 'string') { throw new TypeError('Path must be a non-empty string'); } const keys = path.split('.'); const result = Array.isArray(obj) ? [...obj] : { ...obj }; let current = result; for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; const nextKey = keys[i + 1]; const isNextKeyNumeric = /^\d+$/.test(nextKey); if (current[key] === null || current[key] === undefined) { current[key] = isNextKeyNumeric ? [] : {}; } else { current[key] = Array.isArray(current[key]) ? [...current[key]] : { ...current[key] }; } current = current[key]; } const lastKey = keys[keys.length - 1]; current[lastKey] = value; return result; } exports.set = set;