4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

この記事誰得? 私しか得しないニッチな技術で記事投稿!

TypeScript で Kotlin っぽいコードを書きたいから NPM ライブラリを作ってみた

Posted at

TypeScript の気になる点

TypeScript で「配列内の偶数だけ合計する」という処理を書こうとすると、次のようなコードになると思います。
私は、この例で少し読みにくく感じる点があると思います。(※個人的意見です)

実装 (1)
const sumOfEvenNums = sum(
    [1, 2, 3, 4, 5].filter((num) => num % 2 === 0)
)
実装 (2)
const  evenNums = [1, 2, 3, 4, 5].filter((num) => num % 2 === 0)
const sumOfEvenNums = sum(evenNums)

実装 (1) は、処理順序は次のようになっていると思います。

  1. [1, 2, ...] というリストを定義する
  2. filter で偶数を取り出す
  3. 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 のとき undefinefalse のときオブジェクトをそのまま返します

"2".takeIf((num) => num % 2 === 0) // undefined
"1".takeIf((num) => num % 2 === 0) // 1

感想

NPM パッケージを公開したのが初めてなので結構苦労しました。
TypeScript も Kotlin も好きな言語なので、今後 TypeScript を使っていて気になる点があったらアップデートしていきたいと思います。

4
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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?