From be27647ff73d1529372a80c3e145f3ee4f229a17 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 26 May 2023 16:51:47 -0300 Subject: use buildKeyStorage to prevent different type for same key --- packages/web-util/src/hooks/useLocalStorage.ts | 70 ++++++++++++++------------ 1 file changed, 39 insertions(+), 31 deletions(-) (limited to 'packages/web-util/src/hooks/useLocalStorage.ts') diff --git a/packages/web-util/src/hooks/useLocalStorage.ts b/packages/web-util/src/hooks/useLocalStorage.ts index 55efd01cb..45b7abd3c 100644 --- a/packages/web-util/src/hooks/useLocalStorage.ts +++ b/packages/web-util/src/hooks/useLocalStorage.ts @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { Codec } from "@gnu-taler/taler-util"; +import { Codec, codecForString } from "@gnu-taler/taler-util"; import { useEffect, useState } from "preact/hooks"; import { ObservableMap, @@ -28,7 +28,26 @@ import { memoryMap, } from "../utils/observable.js"; -export interface LocalStorageState { +declare const opaque_StorageKey: unique symbol; + +export type StorageKey = { + id: string; + [opaque_StorageKey]: true; + codec: Codec; +}; + +export function buildStorageKey( + name: string, + codec?: Codec, +): StorageKey { + return { + id: name, + codec: codec ?? (codecForString() as Codec), + [opaque_StorageKey]: true, + }; +} + +export interface StorageState { value?: Type; update: (s: Type) => void; reset: () => void; @@ -50,59 +69,48 @@ const storage: ObservableMap = (function buildStorage() { //with initial value export function useLocalStorage( - key: string, - options?: { - defaultValue: Type; - codec?: Codec; - }, -): Required>; + key: StorageKey, + defaultValue: Type, +): Required>; //without initial value export function useLocalStorage( - key: string, - options?: { - codec?: Codec; - }, -): LocalStorageState; + key: StorageKey, +): StorageState; // impl export function useLocalStorage( - key: string, - options?: { - defaultValue?: Type; - codec?: Codec; - }, -): LocalStorageState { + key: StorageKey, + defaultValue?: Type, +): StorageState { function convert(updated: string | undefined): Type | undefined { - if (updated === undefined) return options?.defaultValue; //optional + if (updated === undefined) return defaultValue; //optional try { - return !options?.codec - ? (updated as Type) - : options.codec.decode(JSON.parse(updated)); + return key.codec.decode(JSON.parse(updated)); } catch (e) { //decode error - return options?.defaultValue; + return defaultValue; } } const [storedValue, setStoredValue] = useState( (): Type | undefined => { - const prev = storage.get(key); + const prev = storage.get(key.id); return convert(prev); }, ); useEffect(() => { - return storage.onUpdate(key, () => { - const newValue = storage.get(key); + return storage.onUpdate(key.id, () => { + const newValue = storage.get(key.id); setStoredValue(convert(newValue)); }); }, []); const setValue = (value?: Type): void => { if (value === undefined) { - storage.delete(key); + storage.delete(key.id); } else { storage.set( - key, - options?.codec ? JSON.stringify(value) : (value as string), + key.id, + key.codec ? JSON.stringify(value) : (value as string), ); } }; @@ -111,7 +119,7 @@ export function useLocalStorage( value: storedValue, update: setValue, reset: () => { - setValue(options?.defaultValue); + setValue(defaultValue); }, }; } -- cgit v1.2.3