TypeScript 遍历对象调用泛型函数时如何实现正确类型推导
问题原因
TypeScript 无法在循环遍历场景下自动推导key和_Map[T]的绑定关系:当key是keyof _Map联合类型时,TS会将fn_map[key]推导为所有回调的联合类型,同时将fn的第二个参数推导为接收1 | "2"的函数,由于函数参数逆变特性,接收窄类型的回调无法赋值给接收宽类型的参数,就出现了你看到的报错。
可行解决方案
方案1:使用泛型辅助遍历函数(最安全,无类型损失)
我们可以写一个专门遍历符合结构对象的泛型函数,让TS在每一次遍历迭代中都能正确绑定key和对应回调的类型关系,全程不需要使用any:
type _Map = { a: 1 b: "2" } type Fn = <T extends keyof _Map>(key: T, cb: (value: _Map[T]) => any) => void let fn!: Fn const fn_map = { a: (v: 1): 1 => 1, b: (v: "2"): "2" => "2" } // 定义通用泛型遍历辅助函数 function traverseMap<T extends object>(map: T, callback: <K extends keyof T>(key: K, value: T[K]) => void) { (Object.keys(map) as Array<keyof T>).forEach(key => { callback(key, map[key]) }) } // 遍历调用,无报错,类型完全安全 traverseMap(fn_map, (key, cb) => { fn(key, cb) }) // fn_map_2的场景同理适配 const fn_map_2 = { a: ["a", (v: 1): 1 => 1] as const, b: ["b", (v: "2"): "2" => "2"] as const } traverseMap(fn_map_2, (k, item) => { const [key, cb] = item fn(key, cb) })
方案2:使用类型断言(更简洁,逻辑确定的场景可用)
如果你可以保证业务逻辑中key和对应回调的匹配关系绝对正确,可以直接用类型断言解决,不需要引入额外函数:
;(Object.keys(fn_map) as Array<keyof _Map>).forEach(key => { fn(key, fn_map[key] as Parameters<Fn>[1]) }) ;(Object.keys(fn_map_2) as Array<keyof _Map>).forEach(k => { const [key, cb] = fn_map_2[k] fn(key, cb as Parameters<Fn>[1]) })
内容的提问来源于stack exchange,提问作者justTryIt
相关产品推荐
相关产品推荐

