Can a TypeScript-typed wrapper for localStorage be created to handle mapped return values effectively?

Is it feasible to create a TypeScript wrapper for localStorage with a schema that outlines all the possible values stored in localStorage? Specifically, I am struggling to define the return type so that it corresponds to the appropriate type specified in the schema. For instance, if I call LocalStorage.get("some_number"), I want the return type to be number. Is achieving this in TypeScript even possible?

The parameter value typed as Keys works effectively for the input!

While attempting to use "type Values = LocalStorageSchema[Keys]" returns a union type of the values, which is not what I require.

Additionally, it appears that using the variable "key" in the get function for type narrowing is not achievable...

I have considered exploring generic types like LocalStorage.get(...) but that might defeat the purpose of specifying the return value type.

Any suggestions on how to approach this issue? Thank you!


type LocalStorageSchema = {
  token: string;
  some_string: string;
  some_number: number;
};

type Keys = keyof LocalStorageSchema;

export const LocalStorage = {
  get(key: Keys): any {
    const data = window.localStorage.getItem(key);

    //type ReturnType = ???
    if (data !== null) {
      return data;
    }

    console.error(`localStorage missing object with key ${key}`);
    return null;
  },

  set(key: Keys, value: any) {
    window.localStorage.setItem(key, value);
  },

  remove(key: Keys) {
    window.localStorage.removeItem(key);
  },

  clear() {
    window.localStorage.clear();
  },
};

Answer №1

Utilize generics to retrieve the correct type based on the key provided!

type LocalStorageSchema = {
    token: string;
    some_string: string;
    some_number: number;
};

type Keys = keyof LocalStorageSchema;

export const LocalStorage = {
    get<T extends Keys>(key: T): LocalStorageSchema[T] | null { // The return type will vary depending on the key
        const data = window.localStorage.getItem(key);

        //type ReturnType = ???
        if (data !== null) {
            return data as LocalStorageSchema[T];
        }

        console.error(`localStorage missing object with key ${key}`);
        return null;
    },

    set<T extends Keys>(key: T, value: LocalStorageSchema[T]) {
        window.localStorage.setItem(key, value as any);
    },

    remove(key: Keys) {
        window.localStorage.removeItem(key);
    },

    clear() {
        window.localStorage.clear();
    },
};

const a = LocalStorage.get('token'); // string | null

Playground

Answer №2

If you need help with handling null values, feel free to check out this link. I haven't fixed all the errors yet, as it's up to you to handle them.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Concealing Querystrings in Node.js and AJAX: A Step-by-Step

I want to create a simple login form using the ajax Post method. However, I am having issues with the querystring still appearing in the URL. Can anyone help me resolve this issue? Thank you for any assistance! [ https://i.stack.imgur.com/R76O4.png http ...

What is the best way to showcase nested array JSON data in an HTML Table?

https://i.stack.imgur.com/OHL0A.png I attempted to access the following link http://jsfiddle.net/jlspake/v2L1ny8r/7/ but without any success. This is my TypeScript code: var viewModel = function(data){ var self = this; self.orders = ko.observableArr ...

Using Jquery & HTML5 for Seamless Transition between Portrait and Landscape Modes

I am working on making my HTML page more user-friendly for tablets. One issue I'm facing is that when the tablet's orientation changes, the menu doesn't hide correctly if the width is less than the height. Here is the code snippet I have so ...

Encountering Duplicate Identifier Error while working on Angular 2 Typescript in Visual Studio Code

Currently attempting to configure a component in Angular 2 with Typescript using Visual Studio Code on Mac. Encounter the following errors when trying the code below: duplicate identifier 'Component'. and Duplicate identifier' DashboardCompo ...

Is it possible to center an anchor link in React JS using Webpack, Sass, and Bootstrap 4?

Recently, I started delving into React JS and Webpack but encountered a perplexing issue. My goal is simple - to center an anchor link on the screen. However, despite trying various methods like inspecting the element, removing inherited styles, setting wi ...

How can we monitor the value of $route.params.someKey in Nuxt.js?

When working with Nuxt.js, I am trying to keep track of the value associated with a key called key1 in the $route.params. The values for key1 are determined using a function called someFunction(). Is there a way for me to monitor $route.params.key1 as a ...

What steps should I follow to set up a TypeScript project that incorporates JavaScript modules compiled from PureScript?

TL;DR I am looking to develop TypeScript typings for compiled PureScript modules and include them in my npm package. I am willing to manually maintain these typings, but I am struggling with the configuration needed in tsconfig.json (up and downstream) and ...

Incorporating a static background image slideshow in ASP.NET - a step-by-step guide

I am currently working on my asp.net website and I would like to incorporate an image slideshow as the background of my homepage. This idea was inspired by a site I came across, . I have successfully implemented the slideshow, but now I am wondering if it ...

Is `h` equal to `createVNode` function?

Both h and createVNode are exposed from vue. The documentation on this page seems to imply that they are interchangeable: The h() function is a utility to create VNodes. It could perhaps more accurately be named createVNode(). However, replacing h with ...

Combining two JSON datasets and presenting the merged information

I need help parsing two sets of json data from the following URLs: https://raw.githubusercontent.com/openfootball/football.json/master/2015-16/en.1.json https://raw.githubusercontent.com/openfootball/football.json/master/2016-17/en.1.json My goal is to di ...

What is the reason behind tsc disregarding the include and exclude options in tsconfig.json?

I am facing an issue with my tsconfig.json file: { "compilerOptions": { "target": "ES6", "lib": [ "DOM", "ES6" ] }, "include": [ "src/server/**/*&q ...

Struggling to find a solution for changing the color of a select box when an option is chosen

Here's an example of the HTML I'm working with: <select onclick="colorchanger()"> <option name="white" value="0">--Select--</option> <option name="red" value="1">Work</option> <option name="green" value="2" ...

Utilize the prototype feature from a versatile source

Can a class with a generic like class Foo<A> {} access A's prototype or use a typeguard on A, or perform any kind of logic based solely on A's type - without being given the class, interface, or instance to Foo's constructor (e.g. when ...

The back button functionality in Android cannot be altered or overridden using JavaScript

Hey everyone, I'm currently in the process of developing a mobile application using phonegap. I'm facing an issue where I want to disable the functionality of the back button from navigating to the previous page. I simply want it to do nothing or ...

JQUERY inArray failing to find a match

I'm at my wit's end working with inArray and I'm really hoping for some help. I am using AJAX to fetch userIDs from my database, which come through as a JSON-encoded array. However, no matter what I try, I always get a -1 when trying to mat ...

employ identical components in v-if and v-else

Currently, I am in the process of designing a login/register page using Vue. The layout includes separate tabs for both login and registration purposes. Here is a snippet of my template code: <transition v-bind:name="TabEffect"> <div ...

The offspring of a React component

How can I select a specific div in children using React without passing it as a prop? I want to transform the code snippet from: <Pane label="Tab 1"> <div>This is my tab 1 contents!</div> </Pane> to: <Pane> <div&g ...

Using the Backbone.js library to make secure requests over https

Currently, I am developing a single page application that involves using Backbone.js and Marionette on the front end, combined with Django and Tastypie on the back end. Recently, I successfully implemented an SSL certificate on the web server and configure ...

Exploring the realm of styling with React JS

Currently, I am facing an issue while working with material-ui for my web design. Here is the code snippet that I am using: const useStyles = makeStyles((theme) => ({ card: { marginTop: theme.spacing(10), direction:"column", alig ...

What is the reason why calling setState does not update the local state?

Hello everyone, I came across an intriguing React task and I'm struggling a bit with finding the solution. Task: Can you figure out why this code isn't working and fix it? Code: class BugFixer extends React.Component { constructor(props) { ...