2
0

TypeScript の関数は関数ではない

Last updated at Posted at 2023-12-19

はじめに

天久保 Advent Calendar 2023 の 9 日目の記事として乱入しました。

TypeScript の関数は関数か

答えは否.なぜかって? 次のコードを見てほしい.

const g = (x: NonNullable<unknown>) => x
const h = () => null

const f = () => h() && g(h())

ただし,NonNullablenullundefined を除外する組み込みの型演算子である (NonNullable<T> = T & {}).これは短絡評価と呼ばれる技法のごく一般的な例であり,特段何も変なところはない.

しかしだ,ここで TypeScript Compiler (TSC) は g(h()) の部分で「 g の引数に null は取れない」と言い出すのである.

Argument of type 'null' is not assignable to parameter of type '{}'.(2345)

「いや,第一項で h() の値が null | undefined の場合を除外してるんだって!」と我は思った。なぜこのようなことが起こるのか。Wikipedia には TypeScript が関数型言語だと書いてあった1のに!

答えは簡単だ。JavaScript の関数は非参照透過的だからである。

エセ関西人による非難の嵐

ここで義務教育を経たエセ関西人から非難の嵐が発生した。それは次のようなものである。

エセ関西人「それは関数やない!!! 小学校のとき,関数とは $$x = y \implies f(x) = f(y)$$ を満たす二項関係であることを習ったはずだろ!!!」

そうなのである。関数であれば,第一項と第二項の h() の返り値が異なってはならないのである。しかし、JavaScript の関数は関数ではない。関数定義で function キーワードを用いることができるからといって、それは数学的な関数とは異なり、呼び出しごとに返り値は変わりうるのである。むしろ、手続き (procedure) のようなものなのだ。現在の TSC 5系 は関数の純粋透過性を判別できず、それが関数か手続きかを理解しない2。したがって、我々は値を代入 (assignment) してから

const g = (x: NonNullable<unknown>) => x
const h = () => null

- const f = () => h() && g(h())

+ const y = h()
+ const f = () => y && g(y)

と書かなければならない。これが JavaScript/TypeScript が純粋関数型言語ではないと言われる所以である。

  1. Wikipedia contributors. (2023, December 15). TypeScript. In Wikipedia, The Free Encyclopedia. Retrieved 20:47, December 19, 2023, from https://en.wikipedia.org/w/index.php?title=TypeScript&oldid=1189970233

  2. 型変数 Htype H = ReturnType<typeof h> とすると,type H = null である.

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0