https://github.com/alexfigliolia/typed-storage
A type-safe wrapper around the browser's LocalStorage and SessionStorage API's
https://github.com/alexfigliolia/typed-storage
local-storage session-storage typescript
Last synced: about 1 month ago
JSON representation
A type-safe wrapper around the browser's LocalStorage and SessionStorage API's
- Host: GitHub
- URL: https://github.com/alexfigliolia/typed-storage
- Owner: alexfigliolia
- Created: 2024-10-08T00:44:30.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2024-10-08T00:54:17.000Z (8 months ago)
- Last Synced: 2025-04-07T05:05:36.197Z (about 2 months ago)
- Topics: local-storage, session-storage, typescript
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/@figliolia/typed-storage
- Size: 48.8 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Typed Storage
A type-safe wrapper around the browser's `LocalStorage` and `SessionStorage` API's. The motivation behind this package is two fold:
1. When working with large teams, ensuring that key-names are consistent and follow certain conventions can be combersome
2. Ensuring that only values of a certain type are stored for each key can require can be difficult because the API's require string-values when storing dataThe `TypedStorage` API allows you define a schema for your data and restricts storing data to only that which matches your key's corresponding value type.
## Installation
```bash
npm i @figliolia/typed-storage
# or
yarn add @figliolia/typed-storage
```## Basic Usage
### Defining Your API
```typescript
import { TypedStorage } from "@figliolia/typed-storage";export interface Schema {
JWT: string;
userId: number;
shoppingCart: { item: string, price: number }[];
}const LocalStorage = new TypedStorage(localStorage);
// or
const SessionStorage = new TypedStorage(sessionStorage);
```### Using Your API
When using your `TypedStorage` instances, your data-type is preserved when setting and getting:```typescript
import { LocalStorage } from "./path/to/myLocalStorage";LocalStorage.setItem("shoppingCart", [
{item: "Bananas", price: 3.00 },
{item: "Apples", price: 2.50 },
// Stringified under the hood
]);const cart = LocalStorage.getItem("shoppingCart"); // parsed under the hood
// { item: string, price: number }[] | nullconst cart = LocalStorage.getItem("cart"); // mispelled key
// Fails typescript validation!
```### Supported Data Types
The `TypedStorage` API supports storing any data-type that is JSON-valid. For keys with values of type `object` or `array`, `JSON.parse()` will be used to deserialize your data upon retreival.For keys with values of type `string` or `number`, best effort parsing is used to determine the correct type on retrieval. For example if the value being retrieved can be safely converted to an integer, float, or `BigInt`, it will be. Otherwise the value will be returned as a string.
For instances where your key-value pair requires a customized serialization or deserialization technique, you can instantiate your `TypedStorage` along with your deserializer mapped to your key:
```typescript
import { TypedStorage } from "@figliolia/typed-storage";interface Schema {
meyKey: Map; // (invalid JSON)
}const MyStorage = new TypedStorage(localStorage, {
meyKey: {
// Convert map to object and stringify it for storage
serialize: (map) => {
const obj: Record = {};
for(const [key, value] of map) {
obj[key] = value;
}
return JSON.stringify(map);
},
// Convert stored object back into a Map for runtime usage
deserialize: (map) => {
const obj = JSON.parse(map);
const result = new Map();
for(const key in obj) {
result.set(key, obj[key]);
}
return result;
}
}
});
```Serializers can also be used in instances where you wish to handle numeric values as strings
```typescript
import { TypedStorage } from "@figliolia/typed-storage";interface Schema {
floatValue: string; // Handle float as strings
}const MyStorage = new TypedStorage(localStorage, {
floatValue: {
// Prevent float-like string from being returned as a number
deserialize: (floatValue) => floatValue;
}
})
```
Because `TypedStorage` parses using a best-effort interpretation of the value, if your string contains only numeric characters, it'll be parsed as a number regardless of your schema definition.If you run into a case such as this and you wish to preserve string-types for numeric values, provide a `serialize` method for that key that simply returns the value as is.
## Advanced Usage
This library also provides an enhancement to the `TypedStorage` API called `LiveStorage`. It works identically to `TypedStorage` with the exception that `LiveStorage` allows you to synchronize your application logic with the data you store:```typescript
import { LiveStorage } from "@figliolia/typed-storage";export interface Schema {
JWT: string;
userId: number;
shoppingCart: { item: string, price: number }[];
}const LocalStorage = new TypedStorage(localStorage);
// or
const SessionStorage = new TypedStorage(sessionStorage);// Let's update our UI whenever our `shoppingCart` changes
const currency = new Intl.NumberFormat('en-us', {
style: 'currency',
currency: 'USD'
});const checkoutUI = document.getElementById("checkout");
LocalStorage.on("shoppingCart", cart => {
if(cart === null) {
// the key was deleted
checkoutUI.textContent = currency.format(0.00);
return;
}// Update your checkout UI's total cost $
const newPrice = cart.reduce((acc, next) => {
acc += next.price;
return acc;
}, 0);
checkoutUI.textContent = currency.format(newPrice);
});
```
In the example above, we'll update our `checkout UI` whenever the user's shopping cart is updated.### When is LiveStorage the better idea?
Use `LiveStorage` in areas where your business logic depends heavily on reads/writes to storage. If your application is performing read/writes in logic that spans multiple features or modules, you may find the that `LiveStorage` API allows you to write more centralized logic in otherwise complex scenarios.