LoginSignup
11
5

More than 5 years have passed since last update.

JavaScript の switch っぽい何かを再発明してみた

Last updated at Posted at 2017-04-25

y13i/switz: Yet another switch-like control structure.

動機

JS の switch のシンタックスがどうにも好きでない

switch - JavaScript | MDN

  • case が変数のスコープをつくらない
  • break を忘れがちでアレ
  • インデントがしっくりこない

Object Literal で代用しようという記事を時々見かける

個人的にはこちらもあまり馴染めず、自分の書きたいシンタックスから仕様を検討した。

実装

実装は TypeScript 、テストスイートは AVA

Switch, Case をクラスとして実装し、 switz という関数はそれらを短い記述で使うためのラッパーとして実装した。

インストール

$ npm install --save switz

使用例

使う前に

import switz from "switz"; // import が使えるならこちら
const switz = require("switz"); // そうでなければ require

基本

const num = Math.ceil(Math.random() * 4);

switz(num, s => {
  s.case(1, () => console.log("ワン!"));
  s.case(2, () => console.log("ツー!"));
  s.case(3, () => console.log("スリー!"));
  s.case(4, () => console.log("よ〜ん"));
});

マッチした case の結果を返すのでより短く書ける

const message = switz(num, s => {
  s.case(1, () => "ワン!");
  s.case(2, () => "ツー!");
  s.case(3, () => "スリー!");
  s.case(4, () => "よ〜ん");
});

console.log(message);

正規表現などでのマッチもできる(デフォルトは switch と同じ === での比較)。さらに matcher の戻り値は case handler の引数として与えられる

import switz, {RegexpMatcher} from 'switz';

const longStr = "lo" + (() => {
  const n = Math.floor(Math.random() * 30);
  let r = "";
  for (let i = 0; i < n; i++) r += "o";
  return r;
})() + "ng";

console.log(longStr); // => "looooooooooooooooooooong"

const message = switz(longStr, s => {
  s.matcher(RegexpMatcher);
  s.case(/o{10,}/, match => `yes, ${match[0].length} "o"s.`);
  s.default(() => "no");
});

console.log(message); // => "yes, 21 \"o\"s."

TypeScript で使う際は Generics を用いて戻りの型を明示できる

const hoge = switz<string>("foo", s => {
  s.case("foo", () => "bar");
  s.case("bar", () => "baz");
  s.case("fuz", () => 123); // `string` でないのでコンパイル時にエラーになる
});

メソッドチェインで書くこともできる

switz("foo", s => s
  .case("foo", () => "bar")
  .case("bar", () => "baz")
);

Switch, Case クラスを直接使って switch builder 的な使い方もできる

const {Switch, Case} = require("switz");
// or
import {Switch, Case} from "switz";

const subject = Math.floor(Math.random() * 100);

const mySwitch = new Switch(subject);

mySwitch.setMatcher((s, c) => {
  const min = c[0];
  const max = c[1];

  return min <= s && max >= s;
});

mySwitch.addCase(new Case([0, 50], () => "Between 0-50"));
mySwitch.addCase(new Case([50, 100], () => "Between 50-100"));

console.log(mySwitch.evaluate());

感想

  • AVA のアサーション が親切すぎて昇天
  • npm にパッケージを publish する時のお作法を習得するのにちょっと手間取った
  • TypeScript かわいい
11
5
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
11
5