mapKeys
EditTransforms an object's own enumerable keys.
/** Converts TypeScript's numeric object keys to their JavaScript runtime form. */export type RuntimeObjectKey<Key extends PropertyKey> = Key extends number ? number extends Key ? string : `${Key}` : Key;
export type MapKeysSourceKey<Source extends object> = RuntimeObjectKey< Extract<keyof Source, PropertyKey>>;
export type MapKeysTransform< Source extends object, MappedKey extends PropertyKey,> = ( this: void, value: Source[keyof Source], key: MapKeysSourceKey<Source>, object: Source) => MappedKey;
/** * Mapped properties are optional because a transform's return type describes * possible keys; collisions and the input's enumerable keys determine which * keys are actually present. */export type MapKeysResult< Source extends object, MappedKey extends PropertyKey,> = Partial<Record<MappedKey, Source[keyof Source]>>;
const readDescriptorValue = ( descriptor: PropertyDescriptor, receiver: object): unknown => { if (Object.hasOwn(descriptor, "value")) return descriptor.value; return descriptor.get ? Reflect.apply(descriptor.get, receiver, []) : undefined;};
/** Transforms own enumerable object keys, with later collisions winning. */export const mapKeys = < Source extends object, MappedKey extends PropertyKey,>( object: Source, transform: MapKeysTransform<Source, MappedKey>): MapKeysResult<Source, MappedKey> => { const result = Object.create(null) as MapKeysResult<Source, MappedKey>; const properties = Reflect.ownKeys(object).flatMap((key) => { const descriptor = Reflect.getOwnPropertyDescriptor(object, key); return descriptor ? [{ key, descriptor }] : []; }); const entries = properties .filter(({ descriptor }) => descriptor.enumerable) .map(({ key, descriptor }) => ({ key, value: readDescriptorValue(descriptor, object) as Source[keyof Source], }));
for (const { key, value } of entries) { Reflect.set( result, transform(value, key as MapKeysSourceKey<Source>, object), value ); } return result;};Download
Section titled “Download”wget -O src/lib/mapKeys.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/functions/mapKeys.tstemp_dir="$(mktemp -d)" && bunx degit jrTilak/lazykit/registry/functions "$temp_dir" && mv "$temp_dir/mapKeys.ts" src/lib/mapKeys.ts && rm -r "$temp_dir"Examples
Section titled “Examples”import { mapKeys } from "./mapKeys";
const upper = mapKeys( { firstName: "Ada", role: "engineer" }, (_value, key) => key.toUpperCase());// { FIRSTNAME: "Ada", ROLE: "engineer" }object(T) — Source object.transform(MapKeysTransform<T, Key>) — Receives the value, runtime string or symbol key, and source object without a callback receiver.- Returns
Partial<Record<Key, T[keyof T]>>with a null prototype. - Later key collisions replace earlier values.