使うときになるとなぜか毎回忘れている気がするのでメモ
何も考えずarrowでoverloadしようとするとこんな感じになるとおもいますが、
type Vec2 = [number, number]
type Vec3 = [number, number, number]
type Negative = ((vec: Vec2) => Vec2) | ((vec: Vec3) => Vec3)
const negative: Negative = (vec: Vec2 | Vec3): Vec2 | Vec3 => {
if (vec.length === 2) {
return [-vec[0], -vec[1]]
}
return [-vec[0], -vec[1], -vec[2]]
}
しかしこれは当然ながらできないです。なぜならnegativeの右辺は型定義上はVec2を受け取ったときにVec3を返す可能性を否定できないし、Vec3を受け取ってVec2を返すかもしれません。左辺ではVec2を受けたら必ずVec2で返す、と言っているのでそれに矛盾します。
一応、TypeScriptでは以下のようなsyntaxでoverloadを使用することができます。
function negative(vec: Vec2): Vec2
function negative(vec: Vec3): Vec3
function negative(vec: Vec2 | Vec3): Vec2 | Vec3 {
if (vec.length === 2) {
return [-vec[0], -vec[1]]
}
return [-vec[0], -vec[1], -vec[2]]
}
ただ、当然arrowのときと同じ問題は抱えています。これではVec2を受けてもVec3を返すかもしれません。
単にtypescriptが型不整合に対して目を瞑っているだけです。
式ではなくfunction文であるから、compilerの都合としてはそういった特殊な推論も差し込めるのだと思います。arrowの場合はどうしても式として使用することになるので、式であれば式として正当な評価/演算ができる必要がありますが、arrowでのoverloadを実現するためにはその仕組みを崩さないといけない(と思う)から現状用意されていないのではないでしょうか。
TypeScriptでは、残念なことに論理的に正しいoverloadをするのは無理だと思います。文法が微妙であるのが原因だと思いますが、TypeScriptは「JavaScriptのコードをそのままTypeScriptに乗せても動作する」ような言語として作られているため、その要件を満たすような文法が発見されてないのなどの原因があるのかなと思いました。
ちなみにタイトルのarrow functionではできないというのは厳密には誤りで、最初の例の右辺項でanyを使えばできます。誰もがanyは可能な限り使いたくないと思うので省略します