最近、こんなコードを書く機会がありました。
import {Promise} from "es6-promise";
interface Entity {
id: number,
name: string
}
class Repository {
deleteEntity(entity: Entity) {
return delete(entity.id)
}
delete(id: number) {
return Promise.resolve(true);
}
}
データ削除の関数を用意するときに、Entity型を受け取るものと、number型を受け取るものをそれぞれ用意しています。deleteEntity(entity: Entity)
はdelete(id: number)
の単純なラッパーなので、戻り値の型は両方ともPromise<boolean>
のはずですね。
確認のために、型をつけてみましょう。
Type 'boolean' is not assignable to type 'Promise'. Property 'then' is missing in type 'Boolean'.
delete(id: number)
の定義は問題ないはずなのに、呼び出し側で「これの戻り値、Promise<boolean>じゃなくてbooleanだよ?」と怒られました。
2つの原因
この件は複数の要因がうまいこと噛み合ってしまったために起きたものでした。次の2つです。
- thisのつけ忘れ
- delete演算子
thisのつけ忘れ
これは私の凡ミスです。自分のクラス内にある関数を呼び出したい場合は、必ずthisをつけないといけないのに、省略してしまっていました。Javaではthisは多くの場合で省略が可能なので、忘れてしまっていたのです。
次のようにちゃんとthisを書いていれば、問題ありませんでした。
deleteEntity(entity: Entity): Promise<boolean> {
return this.delete(entity.id)
}
しかし通常は、単にthisを書き忘れただけならば、存在しない関数を呼ぼうとしているということで、それはそれでコンパイラに叱られるはずなのです。まだ、booleanが返る現象の説明がついていません。グローバル空間にbooleanを返すdeleteが存在しているはずなのです。
delete演算子
今回初めて知りましたが、JavaScriptにはdelete演算子というものがあります。オブジェクトからプロパティを削除してくれるそうです。
このdelete演算子はbooleanを返します。booleanを返します。大事なことなので二回言いました。
さて、ここで生成されたJSコードを見てみましょう。
"use strict";
var es6_promise_1 = require("es6-promise");
var Repository = (function () {
function Repository() {
}
Repository.prototype.deleteEntity = function (entity) {
return delete (entity.id);
};
Repository.prototype.delete = function (id) {
return es6_promise_1.Promise.resolve(true);
};
return Repository;
}());
特に注目すべき点はここです。
return delete (entity.id);
よく見ると、deleteの後ろにスペースがひとつ入っています。TypeScriptさんが気を利かせて入れてくれたんですね。ということは、この式の意味合いは関数呼び出しではなく、delete演算子をentity.id
に対して適用する、というものになります。entity内のオブジェクトからidプロパティを消そうとして、その成否をbooleanで返してくれるんですね! やったね!
やったねじゃないですね。今回は敢えて生成後のJSやd.tsもコミットに入れていたおかげで、プルリクのレビューで同僚の@circled9さんから指摘してもらえたからよかったものの、このまま通っていたら大惨事でした。
反省
- 自分が使う言語の予約語くらいは覚えておこう(参考)
- 型推論に頼りすぎず、自明なもの以外は戻り値の型を指定する習慣を身につけよう
- 今回のケースは本来かなり自明だったはずなんですけどね・・・
- thisの省略のようなJavaのクセを捨てて、JavaScript(ES6)に合ったクセを育ててTypeScriptを書こう
まとめ
型推論、便利だけどこわいなーと思いました(こなみ
追記
「テスト書けよ」
アッハイ