Подтвердить что ты не робот

Расширение экземпляров/статических функций на существующих прототипах с помощью TypeScript

Недавно я задал вопрос о возможности TypeScript расширять существующие прототипы в JavaScript API (здесь: Расширение Object.prototype с помощью TypeScript).

Это оказалось ошибкой, которая с тех пор была решена как TypeScript 0.9.0 Alpha (которая теперь включает в себя дженерики... GREAT: -))

В 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 foo again!
}

Но я не могу это сделать в TypeScript.

Сначала я попытался выяснить, было ли открыто объявление объекта (как с интерфейсами):

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 (я на работе, поэтому я на самом деле не пробовал ее полностью).

Может ли кто-нибудь пролить свет на это?

4b9b3361

Ответ 1

Так как TypeScript 1.4 статические расширения могут быть легко добавлены. Команда TypeScript сменила файл lib.d.ts на использование интерфейсов для всех статических определений типов.

Определения статического типа называются как [Type]Constructor. Поэтому, если вы хотите добавить статическую функцию для ввода Object, добавьте свое определение в ObjectConstructor.

Определение:

interface ObjectConstructor
{
    FooAgain(): void;
}

Реализация:

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

Ответ 2

Проблемы, с которыми вы сталкиваетесь, следующие:

Объявления переменных не открыты, как интерфейсы, поэтому вы не можете добавлять свойства к существующим declare var ....

Поскольку это declare var, а не declare class, вы не можете расширять объект, используя наследование.

Таким образом, вы не можете получить полный опыт от TypeScript в этом сценарии. Вы можете получить компромисс:

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

Object['FooAgain']();

Если вам нужен полный TypeScript опыт, я рекомендую вам создать класс для размещения статических методов - они никак не работают с экземпляром, так что при этом мало вреда:

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

Custom.Object.FooAgain();

Ответ 3

UPDATE

Теперь это возможно, так как TS 1.4. См. "Стефан ответ ниже

LEGACY

У меня есть эта ошибка уже некоторое время: https://typescript.codeplex.com/workitem/917

В одном решении, которое команда typescript могла бы иметь (без расширения спецификации языка), использовались интерфейсы для статических членов и конструкторов: 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