TypeScript为何无法在组合类型中推断返回类型?
嗨,这个问题我之前也碰到过,咱们一步步来拆解:
为什么compose里类型推断会失效?
TypeScript的类型推断逻辑是单向的,对于compose这种从右往左执行的函数组合,它没办法自动把右侧函数的输出类型反向传递给左侧的匿名函数参数。
具体到你的例子:
- 最右侧的
getRecord能被推断为返回RecordJson,接下来的(rec) => rec也能继承这个类型; - 但到了
getIdentifier,它的返回类型是Pick<RecordJson, 'type' | 'id'>,TS没办法把这个类型自动“回溯”给左边的(identifier) => identifier的参数——因为这个匿名函数没有显式标注类型,TS不知道该从哪里获取它的输入类型约束,导致整个链条的类型推断断裂,最终identifier被推断为any,自然就失去了id的类型约束。
TypeScript未来会支持这种特性吗?
目前来看,短期之内原生支持的可能性不大。这种场景需要双向类型推断(同时从左到右和从右到左推导类型),而TS的类型系统目前还是以单向推断为主。
虽然TS团队一直在优化类型推断能力(比如4.9版本增强了函数返回值的推断),但高阶函数组合的全链条自动推断涉及到非常复杂的类型计算,尤其是当组合的函数数量不固定时,需要对高阶类型(HKT)有更完善的支持,这在TS的 roadmap 里还没有明确的优先级。
解决办法:让类型推断重新工作
这里有几个实用的方案,你可以根据场景选择:
1. 给中间匿名函数显式标注类型
直接告诉TSidentifier的类型,让推断链条重新连接:
// 先定义好getIdentifier的返回类型(或者直接写Pick<RecordJson, 'type' | 'id'>) type Identifier = ReturnType<typeof getIdentifier>; const run = compose( (identifier: Identifier) => identifier, // 显式标注类型 getIdentifier, (rec) => rec, getRecord );
2. 换用pipe代替compose
pipe是从左到右执行的函数组合,更符合TS的单向推断逻辑。把函数顺序调整后,TS能自动从左到右传递类型:
const run = pipe( getRecord, (rec) => rec, getIdentifier, (identifier) => identifier // 这里identifier的类型会被自动推断出来 );
3. 给compose定义精确的泛型约束
如果是你自己实现的compose函数,可以给它添加对应数量的泛型参数,明确每个函数的输入输出类型:
// 以4个函数组合为例 function compose<D, A, B, C>( fn1: (input: B) => C, fn2: (input: A) => B, fn3: (input: D) => A, fn4: () => D ): () => C { return () => fn1(fn2(fn3(fn4()))); } // 此时TS能自动推断每个泛型参数 const run = compose( (identifier) => identifier, getIdentifier, (rec) => rec, getRecord );
不过这种方式只适合固定数量的函数组合,可变长度的compose还是需要显式标注类型。
4. 提前绑定类型到getIdentifier
如果pick是柯里化的函数,可以提前让它绑定具体的对象类型,再传入compose:
// 假设pick是柯里化的,先指定要Pick的类型 const getIdentifier = pick<RecordJson>()(['type', 'id']); const run = compose( (identifier) => identifier, // 此时能推断出identifier的类型 getIdentifier, (rec) => rec, getRecord );
内容的提问来源于stack exchange,提问作者Michiel de Vos
相关产品推荐
相关产品推荐

