TypeScript中键控对象的通用访问封装问题
解决方案:通过泛型解耦类库与具体State接口
这是个很常见的类库封装问题——核心就是把具体的State依赖转化为泛型参数,让类库只关心通用逻辑,而把具体的类型定义交给使用它的项目。这里有两种简洁的实现方式,适配不同的场景:
方式1:泛型函数直接传入State
如果你的项目中state不是全局单例,或者每次调用都需要指定不同的状态实例,可以直接把state作为参数传入泛型函数:
// 类库中的通用代码 export function getData<S, T extends keyof S>(state: S, name: T): S[T] { return state[name]; }
项目中的使用示例
// 项目自定义的State和实例 interface A {}; interface B {}; interface State { a: A[]; b: B[]; } const state: State = { a: [], b: [] }; // 调用时自动推断类型 const aData = getData(state, 'a'); // 类型自动推导为A[] const bData = getData(state, 'b'); // 类型自动推导为B[]
方式2:工厂函数创建绑定State的Getter
如果你的场景和原来一样,state是全局单例,希望调用getData时不用每次传state,可以用工厂函数提前绑定状态实例,返回一个类型安全的Getter:
// 类库中的通用代码 export function createDataGetter<S>(state: S) { return function getData<T extends keyof S>(name: T): S[T] { return state[name]; }; } // 也可以抽取出Getter类型,让定义更清晰 export type DataGetter<S> = <T extends keyof S>(name: T) => S[T];
项目中的使用示例
// 项目自定义的State和实例 interface A {}; interface B {}; interface State { a: A[]; b: B[]; } const state: State = { a: [], b: [] }; // 创建绑定了当前state的getData函数 const getData = createDataGetter(state); // 调用方式和原来完全一致,类型推断保留 const aData = getData('a'); // 类型为A[] const bData = getData('b'); // 类型为B[]
这两种方式都能让你的类库彻底脱离对具体State接口的依赖,同时完全保留原有的类型安全和自动推断能力,适配不同项目的自定义状态结构。
内容的提问来源于stack exchange,提问作者Jens Ravens
相关产品推荐
相关产品推荐

