事象
Angular4.3で追加されたHttpClientModuleに移行せず、HttpModuleを使い続けているアプリで、とある理由からpackage-lock.jsonを削除してnpm installし直しました。
ビルド後、HTTP通信を行うとブラウザコンソールに以下のエラーが発生して通信に失敗してしまいます。
ERROR TypeError: this.http.post(...).timeout is not a function
(snip)
原因
RxjsがバージョンアップされたことによってObservableオブジェクトの構成方法が変わった為です。新しいバージョンのObservable.prototypeにはtimeoutメンバがデフォルトでは含まれません。
対処
HttpModuleを使用しているtsファイルで「rxjs/add/operator/timeout」をimportすることでObservable.prototypeにtimeoutメンバが追加され、timeout関数が使えるようになります。
import 'rxjs/add/operator/timeout';
再度ビルド実行して事象のエラーが発生しなくなることを確認します。
まとめ
ちょっと深掘りしてインポートした「node_modules/rxjs/add/operator/timeout.js」を見てみます。Observable.prototype.timeoutに「node_modules/rxjs/operator/timeout.js」を突っ込んでます。
"use strict";
var Observable_1 = require('../../Observable');
var timeout_1 = require('../../operator/timeout');
Observable_1.Observable.prototype.timeout = timeout_1.timeout;
//# sourceMappingURL=timeout.js.map
requireされた「node_modules/rxjs/operator/timeout.js」 を見てみるとtimeout関数が定義されています。
function timeout(due, scheduler) {
if (scheduler === void 0) { scheduler = async_1.async; }
var absoluteTimeout = isDate_1.isDate(due);
var waitFor = absoluteTimeout ? (+due - scheduler.now()) : Math.abs(due);
return this.lift(new TimeoutOperator(waitFor, absoluteTimeout, scheduler, new TimeoutError_1.TimeoutError()));
}
exports.timeout = timeout;
(snip)
この関数がObservableに追加されることで今まで通りtimeout関数を呼べるようになります。
しかしNode.js使ったアプリでpackage-lock.jsonをリセットすると、バージョン齟齬というスリルたっぷりのアトラクションをもれなく味わえますね。
日本でも話題になったこのツイートを思い出しました。
「なぜプログラマは料理が好きか。人参の皮をむき、切ってシチューに入れた後、皮をむくのに使ったピーラーが数バージョンのバージョンダウンをしていて、ピーラーのメーカーが人参4.3のサポートを打ち切っていたことに後から気付く、なんてことが料理には無いから。」
Randallさんのユーモア素敵です。