使用TypeScript在现有原型上扩展实例/静态函数

时间:2013-05-29 14:19:24

标签: javascript prototype typescript

我最近问了一个关于TypeScript在JavaScript API中扩展现有原型的能力的问题(这里:Extending Object.prototype with TypeScript)。

这结果是一个bug,从那时起就被解决了TypeScript 0.9.0 Alpha(现在包括泛型......很棒: - ))

在TypeScript中,接口是开放式的,因此如果查看 lib.d.ts ,您将找到一个定义JavaScript的Object API合约的接口。您还应该看到Object的变量声明,它定义了Object的静态函数。

为简单起见,这里是:

//Pulled from lib.d.ts

interface Object {
    toString(): string;
    toLocaleString(): string;
    valueOf(): Object;
    hasOwnProperty(v: string): bool;
    isPrototypeOf(v: Object): bool;
    propertyIsEnumerable(v: string): bool;
    [s: string]: any;
}

declare var Object: {
    new (value?: any): Object;
    (): any;
    (value: any): any;
    prototype: Object;
    getPrototypeOf(o: any): any;
    getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor;
    getOwnPropertyNames(o: any): string[];
    create(o: any, properties?: PropertyDescriptorMap): any;
    defineProperty(o: any, p: string, attributes: PropertyDescriptor): any;
    defineProperties(o: any, properties: PropertyDescriptorMap): any;
    seal(o: any): any;
    freeze(o: any): any;
    preventExtensions(o: any): any;
    isSealed(o: any): bool;
    isFrozen(o: any): bool;
    isExtensible(o: any): bool;
    keys(o: any): string[];
}

所以,我之前的问题是关于扩展Object的接口,如下所示:

interface Object {
    GetFoo(): Foo;
}

Object.prototype.GetFoo = function() {
    return new Foo();
}

如上所述,这适用于TypeScript 0.9.0。

但是现在我也希望能够向Object添加静态函数,在纯JavaScript中完全合法。

在JavaScript中我会这样做:

Object.FooAgain = function () {
    // Yes, it's foo again!
}

但我似乎无法在TypeScript中完成此任务。

首先,我试着看看Object的声明是否是开放的(与接口一样):

declare var Object: {
    FooAgain(): void;
}

Object.FooAgain = function () {
    // TS doesn't like this, and Object.FooAgain isn't available in intellisense.
}

我也尝试过(我在另一篇文章中看到了这一点,并认为值得一试)。

export declare var Object: {
}

但这似乎打破了一切......

不可否认,这个问题也可能已经在TS 0.9.0中修复了(我正在工作,所以我还没有完全尝试过它。)

任何人都可以对此有所了解吗?

3 个答案:

答案 0 :(得分:14)

因为可以轻松添加TypeScript 1.4静态扩展。 TypeScript团队更改了lib.d.ts文件,以便为所有静态类型定义使用接口。

静态类型定义的名称都与[Type]Constructor类似:因此,如果要添加静态函数以键入Object,请将定义添加到ObjectConstructor

定义:

interface ObjectConstructor
{
    FooAgain(): void;
}

实现:

Object.FooAgain = function(): void
{
    // Oh noes, it's foo again!
}

答案 1 :(得分:3)

您遇到的问题如下:

变量声明不像接口那样打开,因此您无法向现有declare var ...添加属性。

因为它是declare var而不是declare class,所以无法使用继承来扩展Object。

因此,您无法在此方案中获得TypeScript的完整体验。你只能得到妥协:

Object['FooAgain'] = function () {
    alert('Again?');
}

Object['FooAgain']();

如果你想要完整的TypeScript体验,我建议你创建一个容纳静态方法的类 - 它们无论如何都不能在实例上运行,所以这样做没有什么害处:

module Custom {
    export class Object {
        static FooAgain() {
            alert('Again?');
        }
    }
}

Custom.Object.FooAgain();

答案 2 :(得分:3)

更新

现在可以从TS 1.4开始。请参阅Stefan的answer below

LEGACY

我现在提出这个错误了一段时间:https://typescript.codeplex.com/workitem/917

打字稿团队可以拥有的一个解决方案(不扩展语言规范)是使用静态成员和构造函数的接口:http://basarat.github.io/TypeScriptDeepDive/#/modellingstatics

基本上如果lib.d.ts有:

//Pulled from lib.d.ts

interface Object {
    toString(): string;
    toLocaleString(): string;
    valueOf(): Object;
    hasOwnProperty(v: string): bool;
    isPrototypeOf(v: Object): bool;
    propertyIsEnumerable(v: string): bool;
    [s: string]: any;
}

interface ObjectStatic {
    new (value?: any): Object;
    (): any;
    (value: any): any;
    prototype: Object;
    ...
}

declare var Object: ObjectStatic; 

然后您可以通过以下方式轻松地将成员添加到Object:

interface ObjectStatic {
    FooAgain(): void;
}

Object.FooAgain = function () {
    // TS would be fine with this. 
}

我刚刚为此创建了一个功能请求:https://typescript.codeplex.com/workitem/1085