TypeScript の気になる点
TypeScript で「配列内の偶数だけ合計する」という処理を書こうとすると、次のようなコードになると思います。
私は、この例で少し読みにくく感じる点があると思います。(※個人的意見です)
const sumOfEvenNums = sum(
[1, 2, 3, 4, 5].filter((num) => num % 2 === 0)
)
const evenNums = [1, 2, 3, 4, 5].filter((num) => num % 2 === 0)
const sumOfEvenNums = sum(evenNums)
実装 (1) は、処理順序は次のようになっていると思います。
-
[1, 2, ...]
というリストを定義する -
filter
で偶数を取り出す -
sum
で合計する
しかし、実際のコードの順序が 3 → 1 → 2 になっていて、処理とコードの順序が一致していません。
実装 (2) は、evenNums
という無駄な一時変数が定義されています。evenNums
が後で使用されるか分からないので、evenNums
を覚えて置く必要があります。もし、後で出てこなかったら覚え損です。
Kotlin のスコープ関数
上記で挙げた気になる点を解決するのが、プログラミング言語 Kotlin のスコープ関数(Scope functions) です。簡単に言うと、スコープ関数は、あるオブジェクトに対して一時的なスコープを作りだす関数です。
例えば、上記の処理「配列内の偶数だけ合計する」は、スコープ関数 let
を使うと次のような感じになります。
処理とコードの順序も一致しており、説明変数もラムダ式 { ... }
内にだけで有効です。
val sumOfEvenNums = listOf(1, 2, 3, 4, 5) // 数値のリスト
.filter { num -> num % 2 == 0 } // 偶数のみをフィルタリング
.let { evenNums -> sum(evenNums) } // フィルタリング結果の合計をする
NPM パッケージ tslin
TypeScript で使えるスコープ関数のパッケージ tslin
を作りました。
TS + Kotlin で tslin
です。
インストール
次のコマンドでインストールできます。
npm install @rakiya/tslin
追加したスコープ関数などの拡張メソッド
スコープ関数も含めて 8 つのメソッドを追加しました。詳しくは、Kotlin のドキュメントを読めば使用法がわかると思います。
- Object (全てのオブジェクトで使用可能)
Object.let<T, R>(block: (_: T) => R): R
Object.also<T>(block: (_: T) => void): T
Object.takeIf<T>(predicate: (_: T) => boolean): T | undefined
Object.takeUnless<T>(predicate: (_: T) => boolean): T | undefined
- Array (配列で使用可能)
Array.isEmpty(): boolean
Array.isNotEmpty(): boolean
Array.indices(): Array<number>
Array.lastIndex(): number
追加したメソッドの解説
let
例で説明した通り、オブジェクトを加工した結果を返すスコープ関数です。
"abc".let((str) => str.toUpperCase()) // ABC
also
処理をメソッドチェーンの間に挟むためのスコープ関数です。
ラムダ式の処理をした後に、受け取ったオブジェクトをそのまま返します。
[1, 2, 3, 4, 5]
.filter((num) => num % 2 === 0) // [2, 4]
.also((nums) => console.log(nums)) // [2, 4]
.indexOf(2) // 0
takeIf
filter
のオブジェクトバージョンです。ラムダ式が true
のときオブジェクトを返します。false
のときは undefined
を返します。
"2".takeIf((num) => num % 2 === 0) // 2
"1".takeIf((num) => num % 2 === 0) // undefined
takeUnless
takeif
の逆の挙動をします。true
のとき undefine
、false
のときオブジェクトをそのまま返します
"2".takeIf((num) => num % 2 === 0) // undefined
"1".takeIf((num) => num % 2 === 0) // 1
感想
NPM パッケージを公開したのが初めてなので結構苦労しました。
TypeScript も Kotlin も好きな言語なので、今後 TypeScript を使っていて気になる点があったらアップデートしていきたいと思います。