在Next.js中使用TypeScript时window.localStorage的正确类型如何设置
Next.js + TypeScript 中 localStorage 类型设置方案
1. 原生基础类型
TypeScript 已经内置了 Storage 接口定义,不需要额外为 window.localStorage 声明基础类型,其默认类型就是 Storage,自带方法的原生类型定义如下:
interface Storage { readonly length: number; clear(): void; getItem(key: string): string | null; key(index: number): string | null; removeItem(key: string): void; setItem(key: string, value: string): void; [name: string]: any; }
2. Next.js SSR 场景兼容
Next.js 服务端渲染阶段不存在 window 对象,直接调用 window.localStorage 会抛出运行时错误,你可以先封装安全调用逻辑,同时保障类型安全:
const getLocalStorage = (): Storage | undefined => { // 仅客户端环境返回 localStorage if (typeof window !== "undefined") { return window.localStorage; } return undefined; }
后续调用该方法获取 localStorage 时,TypeScript 会自动提示你做非空判断,避免运行时报错。
3. 自定义存储字段的类型约束
原生 localStorage 读写只支持字符串类型,如果你需要为业务自定义存储字段做类型限制,可以提前定义存储字段的类型映射,再封装带泛型的读写工具:
第一步:定义存储字段类型映射
// 按照业务需求定义所有存储key对应的value类型 type LocalStorageKeyMap = { userInfo: { id: number; username: string; avatar: string; }; theme: "light" | "dark" | "system"; visitedIds: number[]; accessToken: string; }
第二步:封装带类型的读写方法
// 读方法 export const getLSItem = <K extends keyof LocalStorageKeyMap>( key: K ): LocalStorageKeyMap[K] | null => { const ls = getLocalStorage(); if (!ls) return null; const value = ls.getItem(key); if (!value) return null; try { // 非字符串类型自动反序列化 return JSON.parse(value) as LocalStorageKeyMap[K]; } catch { // 兼容纯字符串类型存储 return value as unknown as LocalStorageKeyMap[K]; } } // 写方法 export const setLSItem = <K extends keyof LocalStorageKeyMap>( key: K, value: LocalStorageKeyMap[K] ): void => { const ls = getLocalStorage(); if (!ls) return; const stringValue = typeof value === "string" ? value : JSON.stringify(value); ls.setItem(key, stringValue); } // 删除方法 export const removeLSItem = <K extends keyof LocalStorageKeyMap>( key: K ): void => { const ls = getLocalStorage(); if (!ls) return; ls.removeItem(key); }
封装完成后调用工具方法时,TypeScript 会自动提示合法的存储key,同时自动校验传入值的类型,读取结果也会自动关联对应类型,不需要额外做类型断言。
4. 扩展原生 Storage 类型(可选)
如果你需要给原生 localStorage 挂载自定义属性或方法,只需要在项目的全局声明文件(比如 typings.d.ts)中扩展 Storage 接口即可:
declare global { interface Storage { // 自定义安全读取方法 safeGet<T>(key: string): T | null; // 自定义安全写入方法 safeSet<T>(key: string, value: T): void; } } export {}
内容的提问来源于stack exchange,提问作者HLEB HLEB
相关产品推荐
相关产品推荐

