Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / pass / utils / object / handler.ts
blob7116ea40a3ae138c58a15d1c774e1f8b388dd753
1 import type { Callback } from '@proton/pass/types';
3 import { partialMerge } from './merge';
5 /** Handles edge-case where object property is a function - in this
6  * case do not allow passing a setter function */
7 type Setter<T, K extends keyof T> = T[K] extends Callback ? T[K] : T[K] | ((prev: T[K]) => T[K]);
9 export type ObjectHandler<T, R = T> = {
10     data: R;
11     get: <K extends keyof T>(key: K) => T[K];
12     merge: (obj: Partial<T>) => ObjectHandler<T, R>;
13     set: <K extends keyof T>(key: K, value: Setter<T, K>) => ObjectHandler<T, R>;
16 /** Creates a handler for the given object, allowing controlled access to its
17  * properties. This promotes a read/write layer over direct object mutation by
18  * passing around a handle instead of the object itself to functions consuming
19  * the underlying data. The object is kept referentially equal under the hood. */
20 export const objectHandler = <T extends object, R extends any = T>(
21     data: T,
22     map?: (data: T) => R
23 ): ObjectHandler<T, R> => {
24     const handler: ObjectHandler<T, R> = {
25         get data() {
26             const obj = Object.freeze({ ...data });
27             return (map?.(obj) ?? obj) as R;
28         },
29         merge: (obj) => {
30             data = partialMerge(data, obj);
31             return handler;
32         },
33         get: (key) => data[key],
34         set: (key, value) => {
35             data[key] = typeof value === 'function' ? value(data[key]) : value;
36             return handler;
37         },
38     };
40     return handler;