如何在TypeScript中为Ramda库的ifElse函数编写准确的类型定义
解决Ramda ifElse函数类型定义推导问题
你原来的类型定义推导失效的核心原因有两点:
- 全局定义的
Pred、Branch类型携带了高阶泛型参数,会阻碍条件类型的反向推断 - 通过
IfElseBase extends ...的条件类型写法无法正确捕获调用时的动态参数类型,导致所有推断结果 fallback 到any
优化后的类型定义
直接将IfElse定义为携带4个泛型参数的函数类型,在调用阶段自动捕获输入对象、判断函数返回值、两个分支函数的返回值类型:
type Prop = <T, K extends keyof T>(k: K) => (o: T) => T[K] // 新的IfElse类型定义 type IfElse = <OBJ, P extends boolean, RT, RF>( pred: (o: OBJ) => P, onTrue: (o: OBJ) => RT, onFalse: (o: OBJ) => RF ) => (o: OBJ) => P extends true ? RT : P extends false ? RF : RT | RF // 基础函数实现 const ifElse: IfElse = null as any const prop: Prop = null as any // 可选优化:将propEq改为返回类型谓词,支持自动类型收缩 const propEq: <T, K extends keyof T, V extends T[K]>(key: K, val: V) => (obj: T) => obj is T & Record<K, V> = (k, v) => (o) => o[k] === v // 测试用例 type Test = { flag: boolean right: "ok", wrong: "urgs" } const input: Test = { flag: true, right: "ok", wrong: "urgs" } const output = ifElse(propEq("flag", true), prop("right"), prop("wrong"))(input) // 此时output类型会被推导为 "ok" | "urgs",符合编译阶段的类型预期 // 如果将Test的flag字段定义为字面量类型true,output会精确推导为"ok"
补充说明
如果你的业务场景中可以确定输入对象的flag字段一定为true,直接将该字段定义为true字面量类型即可得到精确的返回类型。搭配类型谓词版本的propEq使用时,两个分支的输入对象类型也会自动收缩,不需要手动做类型断言。
内容的提问来源于stack exchange,提问作者Andreas Herd
相关产品推荐
相关产品推荐

