You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决TypeScript柯里化函数参数被推断为unknown的类型问题

问题原因与解决方案

根因分析

TypeScript 的泛型参数推断是按函数调用顺序即时执行的:你调用第一层函数 select(i => i.name) 时,还没有传入第二个数组参数,此时没有任何上下文可以推导泛型 T 的类型,TS 会直接将 T 推断为 unknown。等到第二层传入 items 时,泛型 T 已经固定为 unknown,自然会报「unknown 上不存在 name 属性」的错误。

这种先传选择器、后传数组的柯里化设计,本身无法实现完全自动的类型推断,因为选择器本身的入参类型需要依赖后续传入的数组类型推导,调用顺序和推断顺序是相反的。


可选解决方案

方案1:保留原柯里化顺序,调用时手动指定泛型

如果业务必须保持「先传选择器、后传数组」的调用顺序,只需要在调用第一层函数时手动标注泛型类型即可:

const select = <T>(selector: (i: T) => T) => (numbers: T[]) => numbers.map(selector);
interface Item { name: string; }
const items: Item[] = [{ name: 'name1' }, { name: 'name2' }];

// 手动指定泛型T为Item,类型正常不报错
select<Item>(i => i.name)(items);

注意:原示例的函数定义中选择器返回值类型为 T,如果你的实际场景需要返回选中的属性值(比如上述代码中返回string类型的name),可以扩展泛型支持自定义返回值:

// 扩展支持返回任意类型的选择结果
const select = <T, R>(selector: (i: T) => R) => (numbers: T[]) => numbers.map(selector);
// 调用时只需指定入参类型,返回值会自动推导
const names = select<Item, string>(i => i.name)(items); // 类型为string[]

方案2:调整柯里化顺序,实现全自动类型推断

把数组作为第一层函数的入参,调用时先传数组,TS 可以直接从数组类型推导出 T 的具体值,后续传入选择器时就能自动识别入参类型,不需要手动标注任何泛型:

// 调整柯里化顺序,先收数组,再收选择器
const select = <T>(numbers: T[]) => (selector: (i: T) => T) => numbers.map(selector);
interface Item { name: string; }
const items: Item[] = [{ name: 'name1' }, { name: 'name2' }];

// 自动推断T为Item,i的类型完全正确
select(items)(i => i.name);

这种方案的开发体验最优,也是社区主流的柯里化工具函数(比如Ramda、Lodash/fp)的通用设计逻辑:把固定/已知类型的参数放在柯里化的前几层,动态/需要推导类型的参数放在后几层。

方案3:放弃柯里化,合并为单函数调用

如果不需要复用选择器,直接把两个参数合并到同一个函数中,TS 会同时匹配两个参数的上下文推导泛型,也能实现自动类型推断:

const select = <T>(numbers: T[], selector: (i: T) => T) => numbers.map(selector);
interface Item { name: string; }
const items: Item[] = [{ name: 'name1' }, { name: 'name2' }];

// 自动推断i为Item类型
select(items, i => i.name);

内容的提问来源于stack exchange,提问作者surajs02

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 20:45:03