Skip to main content

Convert Object Values

Converts specified values in objects or arrays of objects between string and number types, supporting nested properties via dot notation.

Import

import { convertObjectValues } from 'nhb-toolbox';

Function Signatures

// Object version
function convertObjectValues<T extends GenericObject, C extends 'string' | 'number'>(
data: T,
options: { keys: DotNotationKey<T>[]; convertTo: C }
): C extends 'string' ? Stringified<T> : Numberified<T>

// Array version
function convertObjectValues<T extends GenericObject, C extends 'string' | 'number'>(
data: T[],
options: { keys: DotNotationKey<T>[]; convertTo: C }
): C extends 'string' ? Stringified<T>[] : Numberified<T>[]

Usage Examples

Convert to Numbers

const product = {
id: "123",
price: "99.99",
meta: { weight: "1.5" }
};

const result = convertObjectValues(product, {
keys: ['price', 'meta.weight'],
convertTo: 'number'
});
// Returns { id: "123", price: 99.99, meta: { weight: 1.5 } }
// Type: Numberified<typeof product>

Convert to Strings

const user = {
id: 456,
profile: { age: 30 }
};

convertObjectValues(user, {
keys: ['id', 'profile.age'],
convertTo: 'string'
});
// Returns { id: "456", profile: { age: "30" } }
// Type: Stringified<typeof user>

Behavior Details

  1. Dot Notation: Supports nested paths like 'user.profile.age'
  2. Type Safety: Maintains proper TypeScript types in return value
  3. Non-Destructive: Returns new object/array without modifying original
  4. Selective Conversion: Only converts specified fields
  5. Array Support: Works with arrays of objects

Limitations

  1. Circular References: May cause stack overflow for deeply nested objects and arrays
  2. Special Types: Dates, RegExp etc. are treated as regular objects
  3. Invalid Numbers: String values that can't convert to numbers are preserved
  4. Performance: Deep cloning may be slow for large structures
  • API response normalization
  • Form data processing
  • Database record preparation
  • Configuration transformation
  • Data migration scripts

Type Definitions

// Result when converting to strings
type Stringified<T> = {
[K in keyof T]: T[K] extends (infer U)[] ? Stringified<U>[]
: T[K] extends object | null | undefined ? Stringified<T[K]>
: T[K] extends string | number ? string
: T[K]
};

// Result when converting to numbers
type Numberified<T> = {
[K in keyof T]: T[K] extends (infer U)[] ? Numberified<U>[]
: T[K] extends object | null | undefined ? Numberified<T[K]>
: T[K] extends string ? number
: T[K] extends number ? T[K]
: number
};

/** - Dot-notation keys for nested objects with `any` value (including optional properties, excluding advanced non-primitive types) */
export type DotNotationKey<T> =
T extends AdvancedTypes ? never
: T extends GenericObject ?
{
[K in keyof T & string]: NonNullable<T[K]> extends GenericObject ?
`${K}` | `${K}.${DotNotationKey<NonNullable<T[K]>>}`
: `${K}`;
}[keyof T & string]
: never;

/** Advanced non-primitive types */
export type AdvancedTypes =
| Array<unknown>
| File
| FileList
| Blob
| Date
| RegExp
| WeakMap<WeakKey, unknown>
| WeakSet<WeakKey>
| Map<unknown, unknown>
| Set<unknown>
| GenericFn
| VoidFunction
| AsyncFunction<unknown>
| Promise<unknown>
| Error
| EvalError
| RangeError
| ReferenceError
| SyntaxError
| TypeError
| URIError
| bigint
| symbol;