如何在泛型createReducer函数中强化TypeScript严格类型检查?
问题
我有一个工具函数createReducer,它接收一个reducer函数并返回该函数:
const createReducer = <T>(reducer: (state: T, action: any) => T) => { return reducer; }; type State = { foo: string; }; createReducer<State>((state) => ({ ...state, bar: 1 // 如何修改`createReducer`让TypeScript在此处抛出错误? }));
在上述示例中,createReducer函数允许我向state对象添加一个未在State类型中定义的新属性bar。我希望当返回的state包含State类型中未定义的属性时,TypeScript能抛出错误。如何实现这种更严格的类型检查?
期望行为示例:
type State = { foo: string }; // 此代码应正常运行 createReducer<State>((state) => ({ ...state, foo: 'updated' })); // 此代码应抛出TypeScript错误,因为`bar`不属于`State`类型 createReducer<State>((state) => ({ ...state, bar: 1 }));
是否可以修改createReducer或其类型定义来实现这种严格类型检查?
解决方案
可以通过约束reducer的返回值必须完全匹配T类型(不允许额外属性)来实现。核心思路是利用TypeScript的类型交叉特性,禁止返回对象包含T之外的属性。
修改后的实现
const createReducer = <T extends object>( reducer: (state: T, action: any) => T & { [K: string]: never } ) => { return reducer; };
原理说明
T & { [K: string]: never }是核心:T保证返回对象的已有属性类型符合定义,{ [K: string]: never }则约束任何额外的字符串键属性类型为never——只要返回对象包含T中没有的属性,就会因类型不匹配触发错误。- 把reducer的返回值类型从宽松的
T改为这个交叉类型,就能强制TypeScript做严格的属性检查。
测试验证
用期望示例测试:
type State = { foo: string }; // 正常运行:仅修改已有属性,符合约束 createReducer<State>((state) => ({ ...state, foo: 'updated' })); // 抛出TypeScript错误:'bar'不在State定义中,与{ [K: string]: never }约束冲突 createReducer<State>((state) => ({ ...state, bar: 1 }));
可选:提取为工具类型
如果需要复用这种严格检查逻辑,可以把约束提取为单独的工具类型:
type Exact<T extends object> = T & { [K: string]: never }; const createReducer = <T extends object>( reducer: (state: T, action: any) => Exact<T> ) => { return reducer; };
效果和简化版完全一致,代码可读性更强。
内容的提问来源于stack exchange,提问作者johann1301s
相关产品推荐
相关产品推荐

