如何动态扩展TypeScript接口适配自定义存储的字段变化?
动态同步TypeScript类型的CustomStorage实现方案
针对静态接口无法匹配动态增删字段的问题,可通过泛型、类型断言与类型扩展的组合方案解决,让TypeScript类型实时跟随CustomStorage的字段变化:
1. 定义泛型基类与类型安全操作方法
创建泛型CustomStorage类,用泛型参数跟踪当前存储字段类型,同时提供类型安全的增删方法:
class CustomStorage<T extends Record<string, any>> { private storage: T = {} as T; // 初始化填充,返回更新类型后的实例 fillStorage<U extends Record<string, any>>(initialData: U): CustomStorage<T & U> { Object.assign(this.storage, initialData); return this as unknown as CustomStorage<T & U>; } // 添加字段,返回更新类型后的实例 addField<K extends string, V>(key: K, value: V): CustomStorage<T & Record<K, V>> { (this.storage as any)[key] = value; return this as unknown as CustomStorage<T & Record<K, V>>; } // 删除字段,返回更新类型后的实例 removeField<K extends keyof T>(key: K): CustomStorage<Omit<T, K>> { delete this.storage[key]; return this as unknown as CustomStorage<Omit<T, K>>; } // 获取字段,类型自动推导 get<K extends keyof T>(key: K): T[K] { return this.storage[key]; } }
2. 扩展window对象的类型声明
在项目类型声明文件(如global.d.ts)中补充window的CustomStorage类型:
declare global { interface Window { customStorage: CustomStorage<{}>; } } export {};
3. 初始化与动态操作的类型同步
通过重新赋值更新window.customStorage的类型,确保TypeScript识别最新字段:
// 初始化填充 window.customStorage = new CustomStorage().fillStorage({ userId: 123, userName: "Alice" }); // 此时TS能识别userId和userName字段 console.log(window.customStorage.get("userId")); // 类型为number // 添加新字段,同步更新类型 window.customStorage = window.customStorage.addField("theme", "dark"); // 此时theme字段已在类型中 console.log(window.customStorage.get("theme")); // 类型为string // 删除字段,同步移除类型 window.customStorage = window.customStorage.removeField("userName"); // 此时userName字段已从类型中移除,访问会触发编译错误 console.log(window.customStorage.get("userName")); // TS编译错误:类型“CustomStorage<{ userId: number; theme: string; }>”上不存在属性“userName”
4. 全局调用的类型一致性
若项目多处调用window.customStorage,可将实例赋值给类型推导后的变量,再挂载到window:
// 初始化后赋值给变量,后续操作基于该变量 let storage = new CustomStorage().fillStorage({ userId: 123 }); storage = storage.addField("theme", "dark"); // 挂载到window时同步类型 window.customStorage = storage;
该方案利用泛型推导、交叉类型与Omit工具类型,让每次增删操作都返回更新后的类型实例,同时通过全局类型声明扩展window对象,彻底消除字段存在性的类型猜测问题。
内容的提问来源于stack exchange,提问作者Lvasche
相关产品推荐
相关产品推荐

