未捕获的TypeError:Typescript扩展方法不是函数

未捕获的TypeError:Typescript扩展方法不是函数,typescript,Typescript,我正在尝试为数组编写一个扩展方法。每当程序运行代码时,我都会得到uncaughttypeerror:pairs.map(…).flatte不是一个函数。下面是代码的样子: 扩展名 declare interface Array<T> { flatten<T>(): T; } Array.prototype.flatten = function<T> () : T { return this.reduce(function (flat: Array&l

我正在尝试为数组编写一个扩展方法。每当程序运行代码时,我都会得到
uncaughttypeerror:pairs.map(…).flatte不是一个函数。下面是代码的样子:

扩展名

declare interface Array<T> {
  flatten<T>(): T;
}

Array.prototype.flatten = function<T> () : T {
  return this.reduce(function (flat: Array<T>, toFlatten: Array<T>) {
    return flat.concat(Array.isArray(toFlatten) ? toFlatten.flatten() : toFlatten )
  }, []);
}
我已尝试将
Array.prototype.flatte=function():T{…
更改为
Array.prototype.flatte=():T=>{…
pairs.map(pair=>pair.start.concat(pair.end)).flatte()
更改为
pairs.map(pair=>pair.start.concat(pair.end)).flatte()
,但它没有做任何事情


我在这里的某个地方也读到过,这可能是一个传输问题,因此我将
--target
编译器更改为
ESNext
,但错误仍然不断出现。

欢迎这样做,b12629不幸的是,TypeScript在编译时加载模块的方式与Javascript加载模块的方式明显不同在运行时编译模块(特别是在使用React或Jest等具有自己的Javascript模块加载系统的框架时)。模块加载系统中的这种差异意味着,即使您的代码已编译,也可能在运行时失败(它是否失败在很大程度上取决于您正在使用的特定框架和模块导入/导出,从而导致非常脆弱的代码)。因此,很难在TypeScript中可靠地使用扩展方法,因此建议使用替代方法(例如帮助器方法、自定义类等)

但是,如果您真的想让扩展方法发挥作用,请继续阅读

基本上,此错误意味着TypeScript在编译时已正确定位接口扩展:

declare interface Array<T> {
  flatten<T>(): T;
}
声明接口数组{
展平():T;
}
但是Javascript没有在运行时执行扩展原型的调用:

Array.prototype.flatten = function<T> () : T {
  return this.reduce(function (flat: Array<T>, toFlatten: Array<T>) {
    return flat.concat(Array.isArray(toFlatten) ? toFlatten.flatten() : toFlatten )
  }, []);
}
Array.prototype.flant=function():T{
返回此.reduce(函数(flat:Array,toFlatten:Array){
返回flat.concat(Array.isArray(toFlatten)?toFlatten.flatten():toFlatten)
}, []);
}
不幸的是,目前接受的答案和StackOverflow上的其他相关答案只提到将定义放在“顶级文件”中,而“顶级文件”并没有给出足够清晰的说明来处理所有场景(请参阅, 及)

若要调试不一致的行为,可以在原型扩展调用上放置断点,以查看何时/是否调用它。还可以检查扩展类的
proto
字段,以检查扩展方法是否已在运行时创建。请记住,由于使用JavaScript来计算这一行


要确保原型扩展调用发生,请找到所有应用程序入口点(例如Jest测试、web framework global等),并确保从每个入口点调用原型扩展调用(粗略的解决方案是在每个入口点的开头调用“setup”方法)。注意:请记住Jest和其他测试库可以模拟模块,因此您希望确保从不模拟调用原型扩展名的模块。实际上,这意味着您应该为扩展名使用单独的文件,并禁用Jest自动模拟(或等效文件).

谢谢!我通过将
展平
定义放在
value.ts
文件的顶部来实现它。我可以将
展平
定义和
接口数组
声明放在1
extensions.ts
文件中吗?如果可以,我应该将
extensions.ts
放在哪里?我已经尝试过将它放在
src
文件夹、
app
文件夹和我创建的
models
文件夹,但我仍然收到运行时错误。我建议保留您的声明(
declare…
)在一个单独的文件中,例如,它可以是
extensions.d.ts
。那么剩下的部分放在哪里完全取决于您自己,只要您在使用原型之前扩展它。它可以在同一个文件中,或者在您调用新定义的函数之前需要的另一个模块中。
Array.prototype.flatten = function<T> () : T {
  return this.reduce(function (flat: Array<T>, toFlatten: Array<T>) {
    return flat.concat(Array.isArray(toFlatten) ? toFlatten.flatten() : toFlatten )
  }, []);
}