177

I noticed that I cannot set boolean values in localStorage?

localStorage.setItem("item1", true);
alert(localStorage.getItem("item1") + " | " + (localStorage.getItem("item1") == true));

Always alerts true | false when I try to test localStorage.getItem("item1") == "true" it alerts true ... How can I set an item in localStorage to true?

Even if it's a string, I thought only === would check the type?

So

alert("true" == true); // should be true? 
brasofilo
  • 25,496
  • 15
  • 91
  • 179
Jiew Meng
  • 84,767
  • 185
  • 495
  • 805

10 Answers10

161

For the moment, all the implementations Safari, WebKit, Chrome, Firefox and IE, are following the current version of the WebStorage standard, where the value of the storage items can be only a string.

An option would be to use JSON parse and stringify method to serialize and deserialize the data, as I suggested some time ago in another question, for example:

var value = "true";
console.log(JSON.parse(value) === true); // true
Matthias
  • 13,607
  • 9
  • 44
  • 60
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 7
    This will obviously break if the string passed in `value` is not valid JSON (for example `JSON.parse("a random string")`) – Adonis K. Kakoulidis Dec 06 '14 at 10:40
  • 7
    True @AdonisK. But if he is using JSON.stringify when setting all values then he is able to offload the responsibility of outputting valid JSON to the library. And that is a very stable library. – Colton McCormack Feb 10 '15 at 21:18
  • 1
    The [current specification](//html.spec.whatwg.org/multipage/webstorage.html#the-storage-interface) defines an interface where `getItem` only returns a string or `null` and `setItem` only accepts a string. Reading the [other answer](/a/3263248/4642212), it doesn’t seem this is going to change, so the wording in this answer is outdated. – Sebastian Simon Oct 20 '21 at 12:09
  • 2
    yeah — it's not an _old_ version, it's _the only_ version. – Matthias Nov 05 '21 at 15:52
89

Firefox's implementation of Storage can only store strings, but on 2009 September, W3C modified the draft to accept any data. The implementation (still) isn't caught up yet (see Edit below).

So in your case the boolean is converted to a string.

As for why "true" != true, as written in the description of Equal (==) in MDC*:

If the two operands are not of the same type, JavaScript converts the operands then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible; else if either operand is a string, the other operand is converted to a string if possible.

Note that the string is converted to a Number instead of a Boolean. Since "true" converted to a number is NaN, it will not be equal to anything, so false is returned.

(*: For the actual standard, see ECMA-262 §11.9.3 “The Abstract Equality Comparison Algorithm”)


Edit: The setItem interface was reverted to accept strings only on the 2011 Sept 1st draft to match the behavior of existing implementations, as none of the vendors are interested in supporting storing non-strings. See https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 for detail.

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • 2
    *If either operand is a number or a boolean, the operands are converted to **numbers** if possible* - I totally didn't realize that. I thought if one were a string, the other was cast to a string. Cheers (+1). – Andy E Jul 16 '10 at 09:01
  • 2
    @Andy, check this [useful notes](http://dmitrysoshnikov.com/notes/note-2-ecmascript-equality-operators/) on the subject. – Christian C. Salvadó Jul 16 '10 at 16:00
21

My solutions:

function tytPreGetBool(pre) {
    return localStorage.getItem(pre) === 'true';
}
Pavel Chuchuva
  • 22,633
  • 10
  • 99
  • 115
tyttoot
  • 211
  • 2
  • 3
  • 3
    @koppor Maybe because if getItem would ever return a boolean, then this method will yield false results, since `true == 'true'` is `false`. – jox Dec 05 '17 at 15:11
  • 9
    ..or plain `localStorage.getItem(pre)==='true'` without the rest – phil294 Apr 10 '18 at 11:17
  • 1
    @koppor why is this down-voted? because the self-righteous stackers are overflowing, literally :) – Ayyash Feb 06 '19 at 07:37
  • 2
    "? true : false" is unnecessary since localStorage.getItem(pre) == 'true' already gives you a boolean result – FelipeDrumond May 13 '19 at 01:33
7

This is related to CMS’s answer.

Here’s a little function I’ve been using to handle the parsing part of this issue (the function will keep doing the Right Thing after the browser implementations catch up with the spec, so no need to remember to change out code later):

function parse(type) {
   return typeof type == 'string' ? JSON.parse(type) : type;
}
brasofilo
  • 25,496
  • 15
  • 91
  • 179
oldestlivingboy
  • 2,914
  • 2
  • 21
  • 15
  • 2
    Isn't this unnecessary compared to JSON.parse? JSON.parse("true") and JSON.parse(true) already both return true, so will still do the right thing after browsers implement boolean localstorage – bscan Apr 22 '17 at 22:50
7

I'd like to point out that it might be kinda easier just to wrap plain boolean value inside object and then, using JSON.stringify create local storage content and other way around, JSON.parse to retrive it:

let storeMe = {
  myBool: true
}

localStorage.setItem('test', JSON.stringify(storeMe))
let result = JSON.parse(localStorage.getItem('test'))

Tomas
  • 3,269
  • 3
  • 29
  • 48
3

Use store.js:

localStorage.setItem('isUser', true)
localStorage.getItem('isUser') === "true" //true
npm i -D store

store.get('isUser')  //true
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
  • 17
    But is it really necessary to include a whole library just for this simple string-to-boolean conversion task? – jayqui Feb 18 '19 at 18:22
2

What I usually do is just save the value in LocalStore as a Boolean, and then retrieve with a parsing method, just to be sure for all browsers. My method below is customized for my business logic. Sometimes I might store smth as 'no' and still need false in return

function toBoolean(str) {
    if (typeof str === 'undefined' || str === null) {
        return false;
    } else if (typeof str === 'string') {           
        switch (str.toLowerCase()) {
        case 'false':
        case 'no':
        case '0':
        case "":
            return false;
        default:
            return true;
        }
    } else if (typeof str === 'number') {
        return str !== 0
    }
    else {return true;}
}
JohnPan
  • 1,185
  • 11
  • 21
1

I'm not sure if LocalStorage can save boolean values but I can tell you that when you do alert("true" == true); it will never evaluate to true because you are implicitly comparing a string to a boolean. That is why to set boolean values you use true instead of "true".

Roman
  • 10,309
  • 17
  • 66
  • 101
  • 1
    What about alert("1"==1)? Javascript is a strange (and inconsistent) beasty. – spender Jul 16 '10 at 08:45
  • @spender: that's because the right operand is cast to a string for the comparison. `"1" === 1` would actually return false. – Andy E Jul 16 '10 at 08:49
  • @Kenny: whoops *facepalm*, thanks for the correction :-) I was mixed up because of how booleans cast to strings. – Andy E Jul 16 '10 at 08:51
1

eval can also be used carefully under some cases.

console.log(eval("true") === true) //true
dlock
  • 9,447
  • 9
  • 47
  • 67
1

When I need to store a flag I usually do:
localStorage.f_active = true (stored value is 'true' and it's fine)
if localStorage.f_active — passes

and to unflag:
delete localStorage.f_active
if localStorage.f_active — doesn't pass (returned value is undefined)

Inversion
  • 1,131
  • 13
  • 19