Расширение экземпляров/статических функций на существующих прототипах с помощью 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 (я на работе, поэтому я на самом деле не пробовал ее полностью).
Может ли кто-нибудь пролить свет на это?
Ответы
Ответ 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