A mock of localStorage written in TypeScript
The other day, I started writing mock of localStorage in TypeScript.
Here is the code that I actually wrote.
Regarding this code, please note that it does not behave completely the same as localStorage.
The behavior is not perfectly reproduced (The value returned when an unintended value is passed, for example), but the basic logic is implemented.
type Store = any;
class LocalStorageMock {
store: Store;
length: number;
constructor() {
this.store = {};
this.length = 0;
}
key(n: number): any {
if (typeof n === 'undefined') {
throw new Error(
"Uncaught TypeError: Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present."
);
}
if (n >= Object.keys(this.store).length) {
return null;
}
return Object.keys(this.store)[n];
}
getItem(key: string): Store | null {
if (!Object.keys(this.store).includes(key)) {
return null;
}
return this.store[key];
}
setItem(key: string, value: any): undefined {
if (typeof key === 'undefined' && typeof value === 'undefined') {
throw new Error(
"Uncaught TypeError: Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 0 present."
);
}
if (typeof value === 'undefined') {
throw new Error(
"Uncaught TypeError: Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 1 present."
);
}
if (!key) return undefined;
this.store[key] = value.toString() || '';
this.length = Object.keys(this.store).length;
return undefined;
}
removeItem(key: string): undefined {
if (typeof key === 'undefined') {
throw new Error(
"Uncaught TypeError: Failed to execute 'removeItem' on 'Storage': 1 argument required, but only 0 present."
);
}
delete this.store[key];
this.length = Object.keys(this.store).length;
return undefined;
}
clear(): undefined {
this.store = {};
this.length = 0;
return undefined;
}
}
export const getLocalStorageMock = (): any => {
return new LocalStorageMock();
};
About localStorage behavior
I actually investigated the behavior of localStorage in the browser before writing this code.
I noticed that it behaved in a slightly interesting way.
For example, the following code.
(I didn't do an exhaustive check, so there may be other unique behaviors hidden in the code)
Note that the environment has been tested with Chrome 94.0.4606.81 (Official Build) (arm64)
.
I haven't tried it with other browsers, so the behavior might be different with different browsers.
window.localStorage.setItem('test', 'aaa')
window.localStorage.key(0)
// => 'test'
window.localStorage.key('a')
// => 'test'
window.localStorage.key(false)
// => 'test'
window.localStorage.key(undefined)
// => 'test'
window.localStorage.key(null)
// => 'test'
Note that if you do not pass any argument to the key function, you will get an error.
window.localStorage.key()
// => Uncaught TypeError: Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.
Here is the MDN documentation on the key function.
https://developer.mozilla.org/ja/docs/Web/API/Storage/key
A mock of localStorage is available on npm
The localStorage mock I wrote at the beginning of this post, written in TypeScript, is available on npm.
@shinshin86/local-storage-mock
Actually, it is helping me write tests for localStorage in another project of mine.
If anyone is considering using it for a similar purpose, please give it a try.
Installation is done like this.
npm install @shinshin86/local-storage-mock
# or
yarn add @shinshin86/local-storage-mock
It can be made to work in this way.
const { getLocalStorageMock } = require('local-storage-mock');
const window = {
localStorage: getLocalStorageMock(),
};
window.localStorage.setItem('testkey', 'testvalue');
console.log(window.localStorage.getItem('testkey'));
// => testvalue
console.log(window.localStorage.key(0));
// => testkey
console.log(window.localStorage.length);
// => 1
window.localStorage.removeItem('testkey');
console.log(window.localStorage.getItem('testkey'));
// => null
window.localStorage.setItem('testkey', 'testvalue');
console.log(window.localStorage.getItem('testkey'));
// => testvalue
window.localStorage.clear();
console.log(window.localStorage.length);
// => 0
console.log(window.localStorage.getItem('testkey'));
// => null
Thanks for reading to the end!
Top comments (0)