TypeScript函数包装器类型兼容问题:如何消除类型报错?
TypeScript钩子注入函数的类型兼容问题解决
我用TypeScript重写旧浏览器扩展时,碰到一个用来包装函数实现「钩子注入」的工具函数。虽然生产环境会换掉它,但想写出能通过TypeScript类型检查的版本,目前代码报类型错误,以下是我写的最优版本:
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return ? Return : never; type GetArgsType<Type> = Type extends (...args: infer Args) => any ? Args : never export function wrapFunction<T, K extends keyof T>( parent: T, name: K, newFunction: ( oldFn: T[K], ...args: GetArgsType<T[K]> ) => GetReturnType<T[K]> ) { var oldFunction = parent[name] parent[name] = (...args:GetArgsType<T[K]>) => { return newFunction(oldFunction, ...args) } return parent[name] }
TypeScript引擎在parent[name] = ...这一行抛出如下报错:
Type '(...args: GetArgsType<T[K]>) => GetReturnType<T[K]>' is not assignable to type 'T[K]'. 'T[K]' could be instantiated with an arbitrary type which could be unrelated to '(...args: GetArgsType<T[K]>) => GetReturnType<T[K]>'.
解决方案
核心问题是原代码没有约束T[K]必须是函数类型,TypeScript无法确定T[K]一定和新函数的类型兼容。我们可以通过泛型约束缩小范围,结合TypeScript内置的类型工具来修复:
// 提取对象中值为函数类型的键 type FunctionKeys<T> = { [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never }[keyof T] export function wrapFunction<T, K extends FunctionKeys<T>>( parent: T, name: K, newFunction: ( oldFn: T[K], ...args: Parameters<T[K]> ) => ReturnType<T[K]> ): T[K] { const oldFunction = parent[name] // 类型断言告知TypeScript新函数与T[K]类型兼容 parent[name] = ((...args: Parameters<T[K]>) => { return newFunction(oldFunction, ...args) }) as T[K] return parent[name] }
说明
FunctionKeys<T>类型用来筛选出对象T中所有值为函数的键,确保K对应的属性一定是函数,避免了类型不确定的问题。- 用TypeScript内置的
Parameters<T>和ReturnType<T>替代自定义的GetArgsType和GetReturnType,更简洁且符合官方规范。 - 最后通过类型断言
as T[K]让TypeScript确认新赋值的函数与原属性类型匹配,解决剩余的类型推导问题。
内容的提问来源于stack exchange,提问作者lawruble13
相关产品推荐
相关产品推荐

