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

Расширение 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, как я могу это исправить?

4b9b3361

Ответ 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 Вы получите больше контроля над этим созданием, и вы также можете добавить дополнительные ограничения.