如何类型安全地使用localStorage?

直接裸用localStorage,简直就是给TypeScript项目埋雷。getItem永远返回string | null,你得手动解析和转换,还老得担心JSON.parse会不会炸。今天咱们聊聊怎么给这个老伙计套上类型安全的鞍具,让它既好用又可靠。

最朴素的办法,是为每一个要存的键,写一个专用的函数。虽然有点笨,但类型绝对安全。

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.stringifyJSON.parse处理对象。第三,对于可能为null的返回值,调用方要做好处理,别直接断言!

还有,别忘了localStorage是同步操作,数据量大了会卡UI。对于复杂应用,可以考虑在上面再封装一层,引入内存缓存或者异步操作,但那是另一个话题了。

总之,别让localStorage成为你类型系统里的法外之地。花半个小时给它做个简单的类型封装,后面能省下无数调试“数据格式不对”的时间。你的代码会感谢你的。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容