reactjstypescriptlocal-storageredux-toolkit

react typescript localstorage Argument of type 'string | null' is not assignable to parameter of type 'string'


I'm doing an app where i use redux toolkit and localstorage to save the theme.

I have this slice :

import { createSlice } from "@reduxjs/toolkit";

const mode = !localStorage.getItem("theme")
  ? ""
  : JSON.parse(localStorage.getItem("theme")); //the error is on this line

const initialState = {
  mode: mode,
};

const ThemeSlice = createSlice({
  name: "theme",
  initialState,
  reducers: {
    toggleTheme: (state) => {
      state.mode = state.mode === "light" ? "dark" : "light";
    },
  },
});

export const { toggleTheme } = ThemeSlice.actions;
export default ThemeSlice.reducer;

but its giving me an error : Argument of type 'string | null' is not assignable to parameter of type 'string'.

What can i do to remove this error?


Solution

  • Issue

    localStorage.getItem("theme") return type is string | null, but JSON.parse expects string, so the type(s) do not match. Even though localStorage.getItem("theme") is evaluated in the ternary condition, Typescript can't tell that localStorage.getItem("theme") in the falsey branch will evaluate to the same value, all it has is the getItem return type of string | null.

    Solution Suggestions

    Nullish Coalescing

    You could use Nullish Coalescing and simply provide a proper string type fallback value to convert null to an empty string.

    const mode = JSON.parse(localStorage.getItem("theme") ?? "");
    

    1st Alternative

    Alternative could be to read and store the theme from localStorage into a variable and use that in the ternary expression, this way the type system references the same value throughout the expression.

    const theme = localStorage.getItem('theme');
    const mode = theme ? JSON.parse(theme) : '';
    

    2nd Alternative

    Optionally, you could assert the value is non-null (!)

    const mode = localStorage.getItem("theme")
      ? JSON.parse(localStorage.getItem("theme")!) // <-- assert non-null
      : "";
    

    But this is only an "escape hatch" if you are 100% absolutely certain localStorage.getItem("theme") won't ever return a null value.

    Between the three options I recommend either of the first two options that stay within the type system safely.