TypeScript and StorageManager
This article explains TypeScript and StorageManager.
We provide practical examples to explain TypeScript and StorageManager.
YouTube Video
TypeScript and StorageManager
What is StorageManager?
StorageManager is an API that allows web applications to estimate how much storage they are using and how much capacity is available. It also provides a persistence request (persist()) to prevent automatic data removal by the user or browser. This allows you to control whether there is enough free space or if data will be automatically deleted, such as when storing large amounts of data in IndexedDB for offline applications.
Feature Detection
First, check whether the browser supports navigator.storage.
1// TypeScript: feature detection for StorageManager
2function supportsStorageManager(): boolean {
3 return typeof navigator !== "undefined" &&
4 typeof navigator.storage !== "undefined" &&
5 typeof navigator.storage.estimate === "function";
6}
7
8// Example usage
9if (supportsStorageManager()) {
10 console.log("StorageManager is supported.");
11} else {
12 console.warn("StorageManager not supported. Falling back to localStorage or IndexedDB.");
13}- This function checks the availability of the StorageManager API in stages.
- Because
navigator.storagedoes not exist in some browsers like Safari, it is important to check its existence safely usingtypeof.
Estimate Storage Usage (estimate())
After checking for functionality with supportsStorageManager(), obtain the usage (usage) and quota (quota) from navigator.storage.estimate().
1// TypeScript: safely get storage estimate
2async function getStorageEstimate(): Promise<{ usage: number; quota: number } | null> {
3 if (!supportsStorageManager()) {
4 console.warn("StorageManager not supported.");
5 return null;
6 }
7
8 const estimate = await navigator.storage.estimate();
9 return { usage: estimate.usage ?? 0, quota: estimate.quota ?? 0 };
10}
11
12// Example usage
13getStorageEstimate().then(result => {
14 if (result) {
15 console.log(`Usage: ${result.usage} bytes / Quota: ${result.quota} bytes`);
16 }
17});- This function always works safely and returns
nullif the browser does not support it. usageandquotaare estimates and may vary between browsers.
Request Data Persistence (persist())
Use persist() to request persistence so that important data (e.g., offline cache) is not subject to automatic deletion by the browser. However, it does not succeed in all environments.
1// TypeScript: safely request persistent storage
2async function requestPersistence(): Promise<boolean> {
3 if (!supportsStorageManager()) {
4 console.warn("StorageManager not supported.");
5 return false;
6 }
7
8 if (typeof navigator.storage.persist !== "function") {
9 console.warn("persist() not available in this browser.");
10 return false;
11 }
12
13 try {
14 const granted = await navigator.storage.persist();
15 return Boolean(granted);
16 } catch (err) {
17 console.error("persist() error:", err);
18 return false;
19 }
20}
21
22// Example usage
23requestPersistence().then(granted => {
24 console.log("Persistence granted?", granted);
25});- If
persist()succeeds, the data will not be automatically deleted by the browser, except by manual user intervention. However, requests can be rejected depending on user actions or browser settings.
Check Available Storage Before Saving Data
Verify available space before saving large data to prevent write failures (QuotaExceededError).
1// TypeScript: ensure enough space before writing
2async function ensureSpaceAndWrite(neededBytes: number, writeFn: () => Promise<void>): Promise<boolean> {
3 const estimate = await getStorageEstimate();
4 if (!estimate) {
5 console.warn("Cannot check storage space. Proceeding without validation.");
6 await writeFn();
7 return true;
8 }
9
10 const free = estimate.quota - estimate.usage;
11 if (free < neededBytes) {
12 console.warn(`Not enough space. Free: ${free} bytes, needed: ${neededBytes} bytes.`);
13 return false;
14 }
15
16 await writeFn();
17 return true;
18}
19
20// Example usage
21ensureSpaceAndWrite(10 * 1024 * 1024, async () => {
22 console.log("Saving large data...");
23});- By checking available storage before saving, you can reduce the risk of write interruptions due to insufficient capacity.
Handling localStorage Type-Safely in TypeScript
localStorage is convenient for storing lightweight configuration data and similar information.
The following class uses generics to create a type-safe wrapper.
1// TypeScript: typed localStorage wrapper
2type Serializer<T> = {
3 serialize: (v: T) => string;
4 deserialize: (s: string) => T;
5};
6
7class TypedLocalStorage<K extends string, V> {
8 constructor(private storage: Storage, private serializer: Serializer<V>) {}
9
10 set(key: K, value: V): void {
11 this.storage.setItem(key, this.serializer.serialize(value));
12 }
13
14 get(key: K): V | null {
15 const raw = this.storage.getItem(key);
16 if (raw === null) return null;
17 try {
18 return this.serializer.deserialize(raw);
19 } catch {
20 return null;
21 }
22 }
23
24 remove(key: K): void {
25 this.storage.removeItem(key);
26 }
27
28 clear(): void {
29 this.storage.clear();
30 }
31}
32
33// Example usage
34const jsonSerializer: Serializer<any> = {
35 serialize: v => JSON.stringify(v),
36 deserialize: s => JSON.parse(s),
37};
38
39const appStorage = new TypedLocalStorage<'theme' | 'token', any>(localStorage, jsonSerializer);
40appStorage.set('theme', { dark: true });
41console.log(appStorage.get('theme'));- This class helps reduce the risk of storing or retrieving data with the wrong type.
Practical Considerations and Best Practices
-
Always check if the browser supports StorageManager Since StorageManager is a relatively new API, always confirm its existence before use.
-
Pay attention to storage limits and compatibility The value returned by
estimate()varies by browser and is only an estimate. -
Design with Asynchronous APIs in Mind
estimate()andpersist()are promise-based asynchronous APIs. Design your code so that you don't block the UI. -
Security Considerations Do not store sensitive information such as access tokens in
localStorage. Consider using HttpOnly cookies or encryption if possible. -
Fallback Design If
supportsStorageManager()returns false, provide a logic to switch to using onlylocalStorageorIndexedDB.
Summary
With feature detection using supportsStorageManager(), you can safely support all environments, check usage and quota with navigator.storage.estimate(), and request persistence with persist(). In TypeScript, use wrapper functions and type definitions to write readable and safe code. The basic flow is: check for existence, estimate, request persistence, and check capacity before writing to storage.
You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.