How to add types to your local storage

3 min read

tl;dr - I go over the basics of interacting with the Storage API and explore a schema based approach to add type safety to it.


With HTML5 browsers introduced the Storage API - a key value storage that stores data in the browser without the need of cookies - with the two implementations localStorage and sessionStorage.


The browsers Storage API can come in very handy but has its limitations:



To make our life a bit easier at lyno - a virtual presence tool - we built a little wrapper for the Storage API which tackles these limitations. In the following sections we will have a look at the basic approach.



Stringify and parse


As mentioned we can only store strings, so if we want to store anything else we need to store its string representation. Fortunately, the browser’s JSON object does this for us; all we need to do is to wrap the getter and setter method of the Storage API. One approach would be to write to helper functions which handle this:

const getLocalStorageItem => (key) {
  return JSON.parse(window.localStorage.getItem(key))
}

const setLocalStorageItem => (key, value) {
  window.localStorage.setItem(key, JSON.stringify(value));
}

This was the easy part which you might have already used in some way or another.



Introducing types


So, we would like to have typings while working with the local storage to actually leverage the advantages of using TypeScript. The approach used here defines a schema which represents the storage and acts as a single source of truth. To achieve our goal, we will also make use of generics. As a quick reminder, generics make it possible to create code components that work over a variety of types rather than a single one.

const identity<T>(arg: T): T => {
  return arg;
}

We define a schema as an interface in which we describe the desired structure of the storage:

interface Schema {
  counter: number;
  message: string;
  user: {
    id: string;
    name: string;
    email: string;
    isAdmin: boolean;
  };
  posts: string[];
}

Next we need getters and setters which will only accept keys and values defined in our schema. As mentioned we use generics to achieve this:

const setTypedStorageItem<T extends keyof Schema>(key: T, value: Schema[T]): void => {
  window.localStorage.setItem(key, JSON.stringify(value));
}

const getTypedStorageItem<T extends keyof Schema>(key: T): Schema[T] | null => {
  return JSON.parse(window.localStorage.getItem(key)) as Schema[T];
}

That’s it, we can now access the local storage in a typesafe way!



Yes, there is a package


You can find a more complete example here which is a package I wrote in context of a project I worked on. I hope this will improve your developer experience and look forward to receive feedback!