直接裸用localStorage,简直就是给TypeScript项目埋雷。getItem永远返回string | null,你得手动解析和转换,还老得担心JSON.parse会不会炸。今天咱们聊聊怎么给这个老伙计套上类型安全的鞍具,让它既好用又可靠。
![图片[1]-如何类型安全地使用localStorage?-速码派](http://www.sumapai.com/wp-content/uploads/2026/01/d05c77e37d0d412aa2498accee46c343_tplv-tb4s082cfz-aigc_resize_1080_1080-1024x683.webp)
最朴素的办法,是为每一个要存的键,写一个专用的函数。虽然有点笨,但类型绝对安全。
const USER_KEY = 'app_user';
interface User {
id: number;
name: string;
}
function getUser(): User | null {
const item = localStorage.getItem(USER_KEY);
if (!item) return null;
try {
return JSON.parse(item) as User;
} catch {
return null;
}
}
function setUser(user: User): void {
localStorage.setItem(USER_KEY, JSON.stringify(user));
}
function removeUser(): void {
localStorage.removeItem(USER_KEY);
}
这么干,getUser的返回值很明确,setUser只接受正确的User对象。坏处是每个存储项都得写这么一套,有点啰嗦。
我们可以做得更通用一点。定义一个存储项的配置映射,用泛型来关联键名和值类型。
interface StorageSchema {
'app_user': User;
'app_settings': { theme: string };
'last_visit': string;
}
function safeGet<K extends keyof StorageSchema>(key: K): StorageSchema[K] | null {
const item = localStorage.getItem(key);
if (!item) return null;
try {
return JSON.parse(item) as StorageSchema[K];
} catch {
return null;
}
}
function safeSet<K extends keyof StorageSchema>(key: K, value: StorageSchema[K]): void {
localStorage.setItem(key, JSON.stringify(value));
}
这样,你用safeGet('app_user'),返回值自动就是User | null;用safeSet('last_visit', 123)就会报错,因为'last_visit'对应的类型是string。类型安全性和复用性都有了。这个StorageSchema接口就是你项目的存储契约,一目了然。
如果你想玩得更花一点,可以结合Proxy或者类封装,做出一个完全类型安全的存储对象,用起来像storage.app_user这样直接访问属性。但我觉得上面那种泛型函数的形式,在简单和实用之间取得了不错的平衡。
这里有几个细节要特别注意。第一,JSON.parse可能会失败,所以try...catch不能少。第二,localStorage只能存字符串,所以记得用JSON.stringify和JSON.parse处理对象。第三,对于可能为null的返回值,调用方要做好处理,别直接断言!。
还有,别忘了localStorage是同步操作,数据量大了会卡UI。对于复杂应用,可以考虑在上面再封装一层,引入内存缓存或者异步操作,但那是另一个话题了。
总之,别让localStorage成为你类型系统里的法外之地。花半个小时给它做个简单的类型封装,后面能省下无数调试“数据格式不对”的时间。你的代码会感谢你的。



























暂无评论内容