TypeScript柯里化函数传入目标对象时如何实现结构类型安全?
问题根源分析
你原来的实现存在两个核心问题:
- 泛型声明时机错误:你将资源类型泛型
T声明在了第一个函数的泛型列表中,但调用第一个函数(传入属性名)时还未传入资源对象,TS无法提前推导T的具体类型,只能默认推导为所有符合{type: ResourceTypes}的联合类型。 - 全属性类型计算错误:你用
keyof Resources[ResourceTypes]['attributes']计算所有属性联合,本质是取所有资源attributes的交集,当不同资源的属性没有重叠时,结果就是never,这就是你新增usergroup后代码直接报错的核心原因。
实现方案
我们只需要调整泛型声明顺序,新增两个工具类型实现属性到资源类型的映射即可:
首先是类型定义部分:
type Resources = { user: { id: string type: 'user' attributes: { name: string age: number last_name: string } }, usergroup: { id: string type: 'usergroup' attributes: { mosterd: string group: string } } } type ResourceTypes = keyof Resources // 分布式遍历所有资源,取所有属性的联合类型 type AllAttributes = { [K in ResourceTypes]: keyof Resources[K]['attributes'] }[ResourceTypes] // 工具类型:根据传入的属性名,反向匹配对应的资源类型 type ResourceByAttribute<A extends AllAttributes> = { [K in ResourceTypes]: A extends keyof Resources[K]['attributes'] ? K : never }[ResourceTypes]
然后是柯里化函数的实现:
function constrain<A extends AllAttributes>(attribute: A) { return (resource: Resources[ResourceByAttribute<A>]) => { // 业务逻辑示例:返回对应属性值 return resource.attributes[attribute] } }
效果验证
// 正常调用,类型推导正确 const userName = constrain('name')({ type: 'user', id: '1', attributes: { name: '小明', age: 20, last_name: '红' } }) // 传入错误资源类型时TS会直接报错 const errorCall = constrain('name')({ type: 'usergroup', // 类型不匹配提示 id: '2', attributes: { mosterd: 'test', group: 'admin' } }) // 不同资源的属性都能正常校验 const groupKey = constrain('group')({ type: 'usergroup', id: '2', attributes: { mosterd: 'test', group: 'admin' } })
内容的提问来源于stack exchange,提问作者Michiel de Vos
相关产品推荐
相关产品推荐

