Design a type-safe generic localStorage wrapper in TypeScript
Preserving compile-time types across localStorage's string-only API.
Generic getItem<T> returns T|null via JSON.parse, setItem<T> stringifies, and a key-to-type map enforces safety.
WHAT THIS TESTS: This question tests whether you can bridge the gap between a runtime API that only stores strings and TypeScript's compile-time type system. The interviewer wants to see that you understand generics are not just for collections, but for preserving type information across serialization boundaries. They also care if you recognize that JSON.parse returns any, so a generic wrapper without runtime validation is only half-safe.
A GOOD ANSWER COVERS: A strong answer proposes a generic class or set of functions where setItem accepts a type parameter T, serializes the value with JSON.stringify, and stores it under a given key. The matching getItem uses the same type parameter T, retrieves the string, calls JSON.parse, and returns T or null if the key is missing. To make the API ergonomic, the candidate should mention mapping keys to specific types via an interface, such as a StorageMap where user maps to User, so that getItem of user automatically returns User without an explicit type argument. The candidate should also note edge cases like JSON.parse throwing on malformed data, handling null returns, and optionally guarding with a runtime validator or schema check since generic type parameters disappear at runtime.
COMMON WRONG ANSWERS: The biggest red flag is returning string or any from getItem and telling the caller to cast the result manually. Another weak pattern is using the any type for the stored value, which erases type information and defeats the purpose of the wrapper. Some candidates forget that localStorage stores only strings and try to return the raw object directly. Others omit null handling entirely, suggesting the method always returns T. A less obvious mistake is forgetting that JSON.parse can throw, leaving the wrapper without error handling.
LIKELY FOLLOW-UPS: The interviewer might ask how you would handle runtime validation since a generic type parameter cannot enforce that the parsed JSON actually matches T. They could ask how to namespace keys to avoid collisions between different features or tabs. Another follow-up is handling storage events to keep multiple tabs synchronized, or implementing a fallback to memory when localStorage is unavailable or in private browsing mode. You might also be asked to add expiration logic or quota exceeded handling.
ONE CONCRETE EXAMPLE: Imagine a StorageMap interface with one property user of type User. The wrapper class is typed with this interface. Calling setItem with key user and a User object serializes it to a string. Later, calling getItem with key user uses the mapped type to know it should return User or null. If the stored string is missing, it returns null. If the string exists but is corrupted JSON, the parse call throws, so the wrapper should wrap JSON.parse in a try-catch and return null or log an error. This gives callers type safety at compile time and graceful degradation at runtime.
Read the original → github.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.