Расширение Object.prototype с помощью TypeScript
В настоящее время я работаю над API TypeScript, который требует некоторых дополнительных функций, связанных с прототипом Object (Object.prototype).
Рассмотрим следующий код:
class Foo {
}
interface Object {
GetFoo(): Foo;
GetFooAsString(): string;
}
//This is problematic...
Object.prototype.GetFoo = function() {
return new Foo();
// Note, this line is just for testing...I don't want my function to just return a blank instance of Foo!
}
//This is ok.
Object.prototype.GetFooAsString = function () {
return this.GetFoo().toString();
}
Возможно, вы захотите попробовать это прямо на Playground.
Как вы можете видеть, у меня есть класс под названием Foo
(а не фактическое имя объекта, которое я буду использовать). Я также расширил интерфейс Object
, чтобы включить две новые функции. Наконец, я реализовал функции против prototype
(эти работы в чистом JavaScript, это просто TypeScript, который жалуется).
Где я записал аннотацию "//это проблематично..." TypeScript выделяет это с красным squiggly и показывает следующую ошибку:
Cannot convert '() => Foo' to '{ (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; }': Call signatures of types '() => Foo' and '{ (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; (): Foo; }' are incompatible
() => Foo
Либо это всего лишь ошибка TypeScript (я знаю, что она все еще находится на стадии разработки, поэтому многие ошибки нуждаются в проглатывании, и я уже проиллюстрировал некоторые из них на CodePlex), или, что-то не хватает.
Почему я получаю эту проблему?
Если это не ошибка TypeScript, как я могу это исправить?
Ответы
Ответ 1
Эта ошибка исправлена в TS 0.9.0 alpha, как вы можете видеть ниже:
![no error in Ts 0.9.0 alpha]()
Игровая площадка все еще работает 0.8.3.
Это в основном происходит потому, что методы на некоторых ключевых интерфейсах (Object, Number, String) и т.д. получают кэширование в качестве оптимизации производительности.
Если вы запустите это. При первом запуске вы не увидите эту ошибку. Попробовать.
Как только вы сделаете редактирование этого кода, парсер снова просмотрит код, и поскольку он кэшировал старое определение интерфейса, он видит дублирующее определение функции и затем эффективно взрывается. Чем больше изменений вы вносите в этот файл, тем сложнее получится сообщение об ошибке.
Ответ 2
Я имел обыкновение иметь:
// See if an array contains an object
Array.prototype.contains = function (obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
чтобы скомпилировать этот код с помощью typescript, я добавил строку:
interface Array {
contains(obj: Object): boolean;
}
Спасибо basarat!
Ответ 3
Я расширил массив таким же образом и столкнулся с большой проблемой, когда сторона использовала for i in ...
для ее перебора. Теперь вы не можете контролировать каждый сторонний код, и эти ошибки могут стать очень раздражающими, поэтому я предлагаю лучший aprocach:
interface Array<T> {
crandom(): T;
}
/** Retrieve a random element from the list */
Object.defineProperty(Array.prototype, 'crandom', { value: function() {
let index = Math.floor(Math.random() * this.length);
return this[index];
}
});
Теперь, используя Object.defineProperty
, ваше новое свойство не будет перечислить, и оно безопасно. Вышеупомянутый код в значительной степени дает случайный элемент из массива. Я сделал еще один, который выдает случайный элемент из массива:
Object.defineProperty(Array.prototype, 'popRandom', { value: function() {
let index = Math.floor(Math.random() * this.length);
let result = this[index];
this.splice(index, 1);
return result;
}
});
с Object.defineProperty
Вы получите больше контроля над этим созданием, и вы также можете добавить дополнительные ограничения.