Typescript: 无法扩展内置类型

创建于 2014-11-14  ·  14评论  ·  资料来源: microsoft/TypeScript

ES6将某些本机对象指定为可子类化,例如Object,Boolean,Error,Map,Promise等。 这些构造在lib.d.ts中建模的方式使子类化成为不可能,因为它们被定义为一对var和一个接口。

根据ES6规范第19.5.1节:

Error构造函数设计为可子类化的。 它可以用作类声明的extends子句的值。 打算继承指定的Error行为的子类构造函数应包括对Error构造函数的超级调用,以初始化子类实例。

当前,这将导致“一个类只能扩展另一个类”错误:

class NotImplementedError extends Error {
    constructor() {
        super("Not Implemented");
    }
}
Bug ES6 Fixed

最有用的评论

如今,即使有扩展Error类的能力,Im在节点上仍然不便。 例如,我在“ error.stack”方面遇到麻烦。 当我执行throw new Error(...)我会得到error.stack ,但是当我执行throw new CustomError() ,我不会。 为了解决这个问题,我不得不使用以下技巧:

export class HttpError extends Error {
    httpCode: number;
    message: string;

    constructor(httpCode: number, message?: string) {
        super();
        if (httpCode)
            this.httpCode = httpCode;
        if (message)
            this.message = message;

        this.stack = new Error().stack;
    }
}

所有14条评论

对于任何公开本来可以归类的函数的js库,这都是一个普遍的问题。 如果我的库导出了Foo构造函数并希望接收Foo的子类实例(而不仅仅是实现Foo式接口的对象),则目前尚无办法允许这样做。

我想说

class Error;

这样的语句不会发出任何javascript,只有Typescript的符号表会更新。

对于一般情况,我希望能够用分号替换任何类声明的主体,从而允许

class Foo<X, Y> extends Bar<X> implements Baz<Y>;

这意味着该库已经保证Foo.prototype是Bar.prototype的实例并实现Baz接口。

@metaweta我认为这可能会带来一些冗余:

interface Foo {
}
class Foo; // Foo is now a class!
interface Bar extends Foo {
}
class Bar extends Foo; // Two `extends Foo`s. 

interface X {
}
class X extends Foo; // Hmm?
interface Y extends Foo {
}
class Y; // Hmm?

它仍然具有一定的潜力,因为可子类化的接口可以作为开放式类使用。 #819

@metaweta您的第一种情况应由环境类声明处理。 例如

// myLib.d.ts
declare class Error {
}
// no code emitted here for this. 
// myfile.ts
// Error is subclassable,
class MyError extends Error {
}

对于第二种情况,我将为此提出另一个建议问题。

这是ES6规范中“可分类的”对象的完整列表。 目前,这些都定义为接口/变量对。

  • 目的
  • 布尔型
  • 错误
  • NativeError
  • 日期
  • 正则表达式
  • 数组
  • TypedArray(Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array和DataView)
  • 地图
  • 弱地图
  • 弱集
  • ArrayBuffer
  • 资料检视
  • 诺言

问题:

  • 将类型定义为类后,就无法扩展成员端(扩展静态端可以通过模块进行)。
  • 成员端的现有扩展无法使用,因为您无法重新定义课程(重大更改)
  • 无法对类(例如,对象,字符串,布尔值,日期,数字,正则表达式,错误和数组)上的函数调用进行建模。 (再次发生重大变化)

可能的解决方案:

  • 允许使用原型属性和构造签名扩展任何类型
  • 允许扩展类的实例端(例如,模块Class.prototype {},由@RyanCavanaugh提供
  • 允许在类构造函数上定义调用签名

@mhegazy谢谢,我没有意识到环境类声明构造。

当我以这种方式(使用环境类定义)扩展Error类时,抛出ExtendedError不会产生堆栈跟踪,也不会正确分配消息。

declare class Error {
  constructor(message?: string);
}

class ExtendedError extends Error {
  constructor(message?: string) {
    super(message + " extended");
  }
}

//throw new Error("Test");
throw new ExtendedError("Test");

@unional,这看起来像是引擎问题。 根据ES6规范,它应该可以正常工作。 既然ES6已获得批准,引擎应该修复这些问题。

我设法使它起作用。 在正在运行的js代码中,我有Error.captureStackTrace调用,但是在ts中实现它时将其取出,因为Error声明没有它。

有一个示例代码:
这是一个类似C#的异常,它带有一个innerException。

declare class Error {
    public name:string;
    public message:string;
    public stack:string;
    constructor(message?:string);
    static captureStackTrace(error: Error, constructorOpt: any);
}

class Exception extends Error {
    public innerException: Error;
    constructor(message?: string, innerException?: Error|string) {
        // Guard against throw Exception(...) usage.
        if (!(this instanceof Exception)) return new Exception(message, innerException);
        super();
        if (typeof Error.captureStackTrace === 'function') {
            //noinspection JSUnresolvedFunction
            Error.captureStackTrace(this, arguments.callee);
        }
        this.name = "Exception";
        if (innerException) {
            if (innerException instanceof Error) {
                this.innerException = innerException;
                this.message = message + ", innerException: " + this.innerException.message;
            }
            else if (typeof innerException === "string") {
                this.innerException = new Error(innerException);
                this.message = message + ", innerException: " + this.innerException.message;
            }
            else {
                this.innerException = innerException;
                this.message = message + ", innerException: " + this.innerException;
            }
        }
        else {
            this.message = message;
        }
    }
}

已由#3516修复。 现在,类可以扩展构造函数类型的任意表达式。

该修复程序将发布哪个版本的TypeScript?
我迅速检查了1.5.3和1.5.4的发行标签,似乎它尚未交付,仅暂时存在于母版中。

编辑:
抱歉,现在已经注意到里程碑“ TypeScript 1.6”标记的错误

感谢您的工作!

@kostrse,您可以通过运行npm install -g typescript@next来试用我们的TypeScript 1.6夜间发行版。

你好

我正在使用打字稿1.6.2和我的lib.es6.d.ts显示错误(和数组,...)作为接口而不是类。
在1.6.2中已经解决了吗?

干杯!

正如@ahejlsberghttps://github.com/Microsoft/TypeScript/issues/1168#issuecomment -112955503中指出的那样, @ jpsfs的修复程序是允许类扩展构造函数类型的任意表达式。

如今,即使有扩展Error类的能力,Im在节点上仍然不便。 例如,我在“ error.stack”方面遇到麻烦。 当我执行throw new Error(...)我会得到error.stack ,但是当我执行throw new CustomError() ,我不会。 为了解决这个问题,我不得不使用以下技巧:

export class HttpError extends Error {
    httpCode: number;
    message: string;

    constructor(httpCode: number, message?: string) {
        super();
        if (httpCode)
            this.httpCode = httpCode;
        if (message)
            this.message = message;

        this.stack = new Error().stack;
    }
}
此页面是否有帮助?
0 / 5 - 0 等级

相关问题

xealot picture xealot  ·  150评论

rwyborn picture rwyborn  ·  210评论

nitzantomer picture nitzantomer  ·  135评论

born2net picture born2net  ·  150评论

disshishkov picture disshishkov  ·  224评论