dot-path-value
Version:
Safely get deep nested properties using dot notation
1 lines • 3.25 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["export type Primitive = null | undefined | string | number | boolean | symbol | bigint;\n\ntype ArrayKey = number;\n\ntype IsTuple<T extends readonly any[]> = number extends T['length'] ? false : true;\n\ntype TupleKeys<T extends readonly any[]> = Exclude<keyof T, keyof any[]>;\n\nexport type PathConcat<TKey extends string | number, TValue> = TValue extends Primitive\n ? `${TKey}`\n : `${TKey}` | `${TKey}.${Path<TValue>}`;\n\nexport type Path<T> = T extends readonly (infer V)[]\n ? IsTuple<T> extends true\n ? {\n [K in TupleKeys<T>]-?: PathConcat<K & string, T[K]>;\n }[TupleKeys<T>]\n : PathConcat<ArrayKey, V>\n : {\n [K in keyof T]-?: PathConcat<K & string, T[K]>;\n }[keyof T];\n\ntype ArrayPathConcat<TKey extends string | number, TValue> = TValue extends Primitive\n ? never\n : TValue extends readonly (infer U)[]\n ? U extends Primitive\n ? never\n : `${TKey}` | `${TKey}.${ArrayPath<TValue>}`\n : `${TKey}.${ArrayPath<TValue>}`;\n\nexport type ArrayPath<T> = T extends readonly (infer V)[]\n ? IsTuple<T> extends true\n ? {\n [K in TupleKeys<T>]-?: ArrayPathConcat<K & string, T[K]>;\n }[TupleKeys<T>]\n : ArrayPathConcat<ArrayKey, V>\n : {\n [K in keyof T]-?: ArrayPathConcat<K & string, T[K]>;\n }[keyof T];\n\nexport type PathValue<T, TPath extends Path<T> | ArrayPath<T>> = T extends any\n ? TPath extends `${infer K}.${infer R}`\n ? K extends keyof T\n ? R extends Path<T[K]>\n ? undefined extends T[K]\n ? PathValue<T[K], R> | undefined\n : PathValue<T[K], R>\n : never\n : K extends `${ArrayKey}`\n ? T extends readonly (infer V)[]\n ? PathValue<V, R & Path<V>>\n : never\n : never\n : TPath extends keyof T\n ? T[TPath]\n : TPath extends `${ArrayKey}`\n ? T extends readonly (infer V)[]\n ? V\n : never\n : never\n : never;\n\nexport function getByPath<T extends Record<string, any>, TPath extends Path<T>>(\n obj: T,\n path: TPath,\n): PathValue<T, TPath> {\n return path.split('.').reduce((acc, key) => acc?.[key], obj) as PathValue<T, TPath>;\n}\n\nexport function setByPath<T extends Record<string, any>, TPath extends Path<T>>(\n obj: T,\n path: TPath,\n value: PathValue<T, TPath>,\n) {\n const segments = path.split('.') as TPath[];\n const lastKey = segments.pop();\n\n let target: T = obj;\n\n for (let i = 0; i < segments.length; i++) {\n const key = segments[i] as TPath;\n if (!(key in target)) {\n target[key] = {} as PathValue<T, TPath>;\n }\n target = target[key];\n }\n\n if (lastKey) {\n target[lastKey] = value;\n }\n\n return obj;\n}\n"],"names":["obj","path","split","reduce","acc","key","value","segments","lastKey","pop","target","i","length"],"mappings":"kBA8DgB,SACdA,EACAC,GAEA,OAAOA,EAAKC,MAAM,KAAKC,OAAO,SAACC,EAAKC,GAAQ,OAAG,MAAHD,OAAG,EAAHA,EAAMC,EAAI,EAAEL,EAC1D,oBAEgB,SACdA,EACAC,EACAK,GAOA,IALA,IAAMC,EAAWN,EAAKC,MAAM,KACtBM,EAAUD,EAASE,MAErBC,EAAYV,EAEPW,EAAI,EAAGA,EAAIJ,EAASK,OAAQD,IAAK,CACxC,IAAMN,EAAME,EAASI,GACfN,KAAOK,IACXA,EAAOL,GAAO,CAAA,GAEhBK,EAASA,EAAOL,EAClB,CAMA,OAJIG,IACFE,EAAOF,GAAWF,GAGbN,CACT"}