TypeScript中为set函数关联自定义设置类型的技术咨询
问题解答
1. 额外类型信息的定义位置
你需要为每个实体(Player、Team)单独定义可更新字段的约束类型,并通过泛型关联到包装类型上,让set函数能根据传入的包装对象推导出对应的合法更新值类型。
具体实现方式:
- 先给每个实体明确可更新规则:
// Player的更新规则:要么只传id,要么同时传name+age type UpdatablePlayer = { id: string } | { name: string; age: number }; // Team的更新规则:仅允许更新name/color字段 type UpdatableTeam = Pick<Team, 'name' | 'color'>; - 建立实体类型到可更新类型的映射,或者用条件类型做推导:
// 类型映射表,关联原实体和对应的可更新规则 type UpdatableMap = { Player: UpdatablePlayer; Team: UpdatableTeam; }; // 或者用条件类型自动匹配 type GetUpdatable<T> = T extends Player ? UpdatablePlayer : T extends Team ? UpdatableTeam : T; // 其他类型默认使用原类型结构 - 最后在set函数中通过这个映射约束参数类型:
function set<T>( propOrObject: MyObjectWrapper<T> | MyPrimitiveWrapper<T>, newValueToSet: GetUpdatable<T> ): T { return {} as T; }
2. 当前结构是否支持实现需求
当前的包装结构可以支持,但需要做针对性扩展:
- 核心是通过类型映射或条件类型,把
MyObjectWrapper<T>和对应的可更新规则绑定,让TypeScript能根据传入的包装对象(比如theTeam属于MyObjectWrapper<Team>),自动推导出newValueToSet必须符合UpdatableTeam的规则。 - 如果需要支持嵌套对象(比如Team里的player1)的细粒度更新规则,还可以进一步扩展
MyPrimitiveWrapper的泛型参数,关联到对应属性的更新约束。
3. 当前实现的不良实践
- 滥用
any类型:set函数的newValueToSet用any完全废弃了TypeScript的类型校验能力,这是最核心的问题。 - 宽泛的原始类型判断:
MyObjectWrapper中用T[P] extends string | number | boolean | any[]判断原始类型,any[]会匹配所有数组(包括对象数组),可能导致本该被包装成MyObjectWrapper的嵌套对象被错误处理成MyPrimitiveWrapper。 - 无意义的硬断言:get和set函数里的
return {} as T属于强制类型断言,完全忽略了返回值和类型T的实际差异,容易引发运行时错误。 - 包装类型未关联更新规则:当前的
MyObjectWrapper只是简单包装原类型的所有字段,没有绑定任何更新约束,导致set函数无法利用包装对象的类型信息做校验。 - 缺失嵌套对象的更新支持:现有结构没有考虑嵌套层级(比如Team下的Player)的更新规则,无法对这类场景做类型约束。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

