Typescript 运行时错误:当扩展 undefined 时无法读取“prototype”属性。

36

所以我在控制台中得到了上述错误。这是由于当它被传递给__extends(在生成的.js中)时,_super未定义引起的。

以下是一些测试代码,可用于重现此错误:

//This is the entirety of the file Test.ts
module Test {
    export class Test1 {
        public Name: string;
        public Number: number;

        constructor() {

        }
    }
}

然后在另一个文件中,我有一个继承自那个类的类:

/// <reference path="Test.ts" />
module Test {
    export class Test2 extends Test1 {
        constructor() {
            super();
        }
    }
}

<reference path... 不应该需要(也确实不需要),但我添加它是为了看看它是否有帮助(但没有)。

文件通过 BundleConfig 以正确的顺序(Test.ts 然后是 Test2.ts)被包含(运行时无论是否进行优化都没有任何影响)。

我可能是一个巨大的新手,但我一点也不知道我搞砸了什么。我在网上找到的所有这个问题的其他实例都是来自使用命令行编译器将多个 TypeScript 文件合并成一个单一文件的人。我正在使用打包程序来完成这个任务,但即使我不将它们组合,我也会遇到完全相同的问题。

请帮帮我,我已经快崩溃了!

如请求所示,这里是编译后的 JavaScript:
Test.js:

//This is the entirety of the file Test.ts
var Test;
(function (Test) {
    var Test1 = (function () {
        function Test1() {
        }
        return Test1;
    })();
    Test.Test1 = Test1;
})(Test || (Test = {}));
//# sourceMappingURL=Test.js.map

Test2.js:

var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
/// <reference path="Test.ts" />
var Test;
(function (Test) {
    var Test2 = (function (_super) {
        __extends(Test2, _super);
        function Test2() {
            _super.call(this);
        }
        return Test2;
    })(Test.Test1);
    Test.Test2 = Test2;
})(Test || (Test = {}));
//# sourceMappingURL=Test2.js.map

1
我在午餐时间重启了我的电脑,现在这个程序可以工作了。非常奇怪。 - Maverick
5个回答

26
可能发生这种情况的原因如下:
  1. 四次检查 BundleConfig 是否按正确顺序连接文件。这是该错误最常见的原因。
  2. 验证您的 Test.ts 文件中没有任何顶级的 export 指令。否则,该文件将成为外部模块,Test1 将不再可见。

如果以上方法都无效,您应该将生成的 JavaScript 发布到问题中,以便我们诊断问题的根本原因。


BundleConfig 只在发布模式下连接文件,但代码的顺序无论如何都是正确的(我甚至尝试手动包含已编译的 .js 文件以确保100%)。我上面发布了我所有的 .ts 文件(我在更复杂的代码中遇到了错误,因此我只使用了上述 TypeScript 创建了一个新页面)。我将用同样的方式处理 .js 文件。 - Maverick
脚本标签在HTML页面上的顺序是什么?您是否设置了断点来查看何时分配内容? - Ryan Cavanaugh
来自页面的HTML: <script type="text/javascript" src="/js/@jsFolder/Home/Test.js"></script> <script type="text/javascript" src="/js/@jsFolder/Home/Test2.js"></script> 我还没有在网页中设置断点,午餐后再试一下。 - Maverick
2
这指引了我正确的方向来解决相同的问题。 - Flinkman
这也对我有所帮助。对于那些将所有类都放在一个文件中并使用多级继承的人,请确保您按照层次顺序将它们放在文件中。例如,如果您有 abstract class Human -> abstract class Homo extends Human -> class Sapien extends Homo,则类定义需要按照相同的顺序放置在文件中:Human、Homo,然后是Sapien。 - Carrie Kendall
显示剩余2条评论

18

今天遇到了这个错误。不确定 OP 场景是什么,但在我们团队的情况下,我们有:

  1. TypeScript v1.8.10
  2. 基于 Webpack 的开发构建,包括合并、源映射,但没有优化/混淆
  3. Angular 2 依赖注入
  4. 基类和派生类均在同一文件中定义(如 dependencies.ts
  5. 派生类定义在基类后面
  6. 没有编译错误或警告
  7. 控制台日志显示 Uncaught TypeError: Cannot read property 'prototype' of undefined
  8. 调用堆栈指向另一个文件(例如 client.ts)中的另一个类的最后一行内部的 __extends 函数,将其作为依赖项导入

代码如下:

// dependencies.ts

import { Injectable } from 'angular2/core';

@Injectable()
export class LocalStorageService extends BaseStorageService {
  constructor() {
    super(localStorage);
  }
}

class BaseStorageService {
  constructor(private storage: Storage) {}
  // ...
}

而且:

// client.ts

import { Injectable } from 'angular2/core';
import { LocalStorageService } from './dependencies';

@Injectable()
export class AuthStorageService {

  constructor(private permanentStorage: LocalStorageService) { }
  // ...

} // <-- call stack pointed here with inner '__extends' function

通过在派生类定义之前定义基类解决了问题。快速搜索和阅读后,这似乎与已知的(未解决的?)TypeScript问题有关,例如#21#1842

希望对你有帮助。


1
正如上面所说,我遇到的问题是某种奇怪的问题,通过重新启动我的电脑解决了。我问题中的代码是我用来产生错误的 - 但是没有任何理由表明该代码和设置会产生错误 :)。 - Maverick
是的,我读过那个帖子,所以我不确定它是否是相同的情况。但错误是相同的,而且其他人也由于类定义的顺序而遇到了该错误。这对那些通过谷歌搜索来到这里的人(例如我)可能会有所帮助。 - superjos
很好的描述!对我来说,我有一个在基类之前定义的未使用的类。因此,问题实际上比你描述的更普遍。 - John Zabroski
我在一个使用Typescript的ionic2项目中遇到了类似的问题。一种常见的导入方式是将它们收集在一个充满导出的单个ts文件中。这就是我们问题的原因,因为其中包含了基类和子类的导出,这些导出有些混乱了导入的顺序。解决方案是将基类从中分离出来(我们还将其移动到另一个文件夹中),并从该文件中显式地导入基类。我们还有一个通用类型的类,它使用此基类作为其类型参数,因此我们的错误显示在使用此通用类的类中。 - Johncl

3

您的HTML中脚本的顺序很重要。

假设您有一个TypeScript文件A.ts,其中定义了一个抽象类,并且有一个文件B.ts,其中包含一个扩展A.ts中抽象类的类。

导出抽象类ShipmentsListScope实现IShipmentsListScope {

A.ts:

module app.example{
  "use strict";

  interface IMyInterface{
    // ..
  } 
  export abstract class MyAbstract implements IMyInterface{
    // ..
  }
}

B.ts

module app.example{
    "use strict";

  class MyChildClass extends MyAbstract {
    // ...
  }
}

然后在你的HTML中,你必须确保脚本的顺序是正确的,一旦Javascript文件被生成:

<script src="/app/example/A.js"></script> <!-- A.js BEFORE -->
<script src="/app/example/B.js"></script>

2

我曾遇到相同的问题,原因是export default语句导致的。为了解决这个问题,我只需删除这些语句并以其他方式导入所需的项目:

之前的代码

A.ts

export default MyClass;

class MyClass { ... }

B.ts

import MyClass from "./A";

class MyClass2 extends MyClass { ... }

AFTER

A.ts

export class MyClass { ... }

B.ts

import { MyClass } from "./A";

class MyClass2 extends MyClass { ... }

1

我在这里分享一下我解决这个问题的方法:我在TS文件顶部缺少了一个引用,虽然构建时没有问题,但在运行时出现了相同的错误。添加看起来是可选的引用解决了我的运行时问题。


@Samuel A 我在我的项目中创建了一个 ts 文件,用 /// <reference /> 引用它。 - bviale

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接