如何在TypeScript中检查传入类型?实现string|undefined的JSON解析优化
如何在TypeScript中实现根据泛型类型调整useLocalStorage的解析逻辑
要实现当泛型参数T为string | undefined时跳过JSON解析/序列化的逻辑,核心要解决两个问题:编译时的类型推断和运行时的逻辑分支——因为TypeScript泛型是编译时信息,运行时无法直接读取泛型类型,所以我们需要结合传入的fallbackValue的运行时类型来做判断。
修改后的完整代码
import { useEffect, useState, Dispatch, SetStateAction } from 'react' type SetValue<T> = Dispatch<SetStateAction<T>> // 函数重载:明确string|undefined类型的分支 export function useLocalStorage<T extends string | undefined>(key: string, fallbackValue: T): [T, SetValue<T>] export function useLocalStorage<T>(key: string, fallbackValue: T): [T, SetValue<T>] export function useLocalStorage<T>(key: string, fallbackValue: T): [T, SetValue<T>] { const [value, setValue] = useState<T>(() => { if (typeof localStorage === 'undefined') { return fallbackValue } const stored = localStorage.getItem(key) if (!stored) { return fallbackValue } // 运行时判断:如果fallback是string或undefined,直接返回存储的字符串 if (typeof fallbackValue === 'string' || fallbackValue === undefined) { return stored as T } // 其他类型执行JSON解析 return JSON.parse(stored) as T }) useEffect(() => { if (typeof localStorage === 'undefined') { return } // 保存时同理:string或undefined直接存储,其他类型序列化 if (typeof value === 'string' || value === undefined) { localStorage.setItem(key, value ?? '') } else { localStorage.setItem(key, JSON.stringify(value)) } }, [key, value]) return [value, setValue] }
关键逻辑说明
- 函数重载:通过重载声明,让TypeScript在传入
string | undefined类型的fallbackValue时,能更准确地推断返回值类型,避免不必要的类型断言。 - 运行时类型判断:
- 读取阶段:检查
fallbackValue的类型,如果是string或undefined,直接返回localStorage中存储的字符串(因为此时T必然是string | undefined);否则执行JSON.parse。 - 保存阶段:检查当前
value的类型,如果是string或undefined,直接存入localStorage;否则执行JSON.stringify。
- 读取阶段:检查
- 类型断言:因为我们已经通过运行时判断确保了类型匹配,所以用
as T做类型断言是安全的。
使用示例
// 字符串类型:自动跳过JSON解析 const [username, setUsername] = useLocalStorage('username', 'default-name') // 对象类型:自动执行JSON解析/序列化 const [userInfo, setUserInfo] = useLocalStorage('user-info', { id: 1, name: 'Alice' }) // undefined类型:直接存储空字符串(也可根据需求调整) const [token, setToken] = useLocalStorage('token', undefined)
内容的提问来源于stack exchange,提问作者János
相关产品推荐
相关产品推荐

