泛型回调中类型推断错误的问题排查与修复请求
TypeScript测量函数执行时间工具的类型系统问题
我正在编写一个通过包装函数测量函数执行时间的工具,但类型系统无法正常工作,我认为自己没出错,请问问题出在哪里以及如何修复?
function logTime(timeMs: number, name: string) { console.log(`Execution of "${name}" took ${timeMs} milliseconds`); } // 我猜问题在这里 export function measureExecutionTime<T, U>(name: string, cb: (...args: T[]) => U, handleTime = logTime) { return function (...innerArgs: T[]) { const start = new Date(); const result = cb(...innerArgs); const end = new Date(); handleTime(end.getTime() - start.getTime(), name); return result; }; } // 这段代码应该正常工作,但报错了:val的类型是"number | number[]"。但val不可能是数组啊? [1, 2, 3].map(measureExecutionTime("square number", val => val**2));
问题原因
你的measureExecutionTime泛型定义存在歧义:用T[]作为回调函数的剩余参数类型时,TypeScript无法确定T代表的是单个参数的类型还是参数数组的元素类型。结合map的回调函数本身可接收3个参数(当前元素、索引、原数组),TypeScript会宽泛推断T为number | number[],导致val的类型出现错误。
修复方案
方案1:仅支持单个参数的场景
如果你的工具主要用于包裹单参数函数,直接将泛型调整为明确接收单个参数:
function logTime(timeMs: number, name: string) { console.log(`Execution of "${name}" took ${timeMs} milliseconds`); } export function measureExecutionTime<T, U>(name: string, cb: (arg: T) => U, handleTime = logTime) { return function (arg: T) { const start = new Date(); const result = cb(arg); const end = new Date(); handleTime(end.getTime() - start.getTime(), name); return result; }; } // 现在val被正确推断为number,代码正常工作 [1, 2, 3].map(measureExecutionTime("square number", val => val**2));
方案2:支持任意数量参数的通用版本
要兼容多参数函数,需要用泛型约束明确剩余参数的类型,让TypeScript正确推断参数列表:
function logTime(timeMs: number, name: string) { console.log(`Execution of "${name}" took ${timeMs} milliseconds`); } export function measureExecutionTime<T extends any[], U>(name: string, cb: (...args: T) => U, handleTime = logTime) { return function (...args: T) { const start = new Date(); const result = cb(...args); const end = new Date(); handleTime(end.getTime() - start.getTime(), name); return result; }; } // 单参数场景正常推断 [1, 2, 3].map(measureExecutionTime("square number", val => val**2)); // 多参数场景也能正确支持 const add = measureExecutionTime("add", (a: number, b: number) => a + b); add(1, 2); // 执行正常,类型检查通过
内容的提问来源于stack exchange,提问作者NoBullsh1t
相关产品推荐
相关产品推荐

