if文駆逐計画 〜30代疲れ目エンジニアの条件分岐作法〜

もう長いことコードを書いていると、「ああ、これまたif文か」と思う瞬間、増えてこない？
それ、わかるよ。若かったあの頃はif文で全てが解決できると思ってたんだよね。あの頃はね。

if文は、ロックみたいなもんさ。無骨で力強く、ガシガシとパワーコードを弾いてる感じでパワーコードを書いてた。
だけど、年を重ねてくると、if文もだんだん胃もたれしてきて、「これ、もう少しいい感じに書けないかな？」って思うことが増えてくるんだよ。
今日はそんな30代の疲れ目エンジニアのための話。

---

### 三項演算子、君は僕の愛だ

まず最初に言わせてほしい。僕は三項演算子が好きだ。いや、正確には**愛している**。`?`と`:`が生み出すあの短さと簡潔さ、条件分岐が一行で完結するところが最高なんだ。これだけでコードがぐっとスマートになる。

例えば、こんなコード(SWRのサイトから引用)：

```jsx
import useSWR from 'swr'
 
function Profile() {
  const { data, error, isLoading } = useSWR('/api/user', fetcher)
 
  if (error) return <div>failed to load</div>
  if (isLoading) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}
```

は三項演算子でこう書ける。

```jsx
import useSWR from 'swr'

function Profile() {
  const { data, error, isLoading } = useSWR('/api/user', fetcher)

  return error ? (
    <div>failed to load</div>
  ) : isLoading ? (
    <div>loading...</div>
  ) : (
    <div>hello {data.name}!</div>
  )
}
```

見て、このスッキリ感。if文では`return`を3回も書かないといけないところを、たった1つの`return`で済ませられる。これが三項演算子の魅力さ。三項演算子は`文`ではなく`式`だからね。
でもね、三項演算子にも限界があるんだ。

---

### ネストの深みで見失うもの

三項演算子、条件が2つ、3つなら全然いいんだ。でも、条件が増えてくると、どうなる？
そう、ネストが深くなって、コードが**追いかけにくくなる**んだよね。

「ちょっと待てよ、何が起きてるんだ？」って脳みそインタプリタがバグる瞬間が来る。コードはシンプルなはずなのに、頭が追いつかない。これはもう、三項演算子の限界さ。

---

### if文、君には感謝してるけど、もう卒業しよう

if文。プログラムを書き始めた頃は頼れる相棒だった。「if文とfor文があれば全ては解決できる」って思ってたよね。懐かしいあの頃だよ。
でも、条件が増えるたびに、if文がどんどん重くなっていく。

```jsx
function UserAccess({ role }) {
  if (role === 'admin') {
    return <AdminDashboard />;
  } else if (role === 'editor') {
    return <EditorPanel />;
  } else if (role === 'viewer') {
    return <ViewerContent />;
  } else {
    return <GuestAccess />;
  }
}
```

これ、最初はわかりやすいよね。でも、条件が増えていくと、if文が積み重なっていく。「これ、if文が無限に続くんじゃないか？」って思った瞬間。それはもう卒業の時が来たんだ。

---

### `Match` と `When`：if文駆逐計画、始動

そこで登場するのが、**`Match`**と**`When`**。if文から解放され、コードをもっとシンプルで読みやすく、整理されたものにできるんだ。

#### Reactの`Match`と`When`の実装

まず、`Match`と`When`を実装しよう。これで条件分岐をReactの中で扱いやすくするんだ。

```jsx
const Match = ({ children }) =>
  React.Children.toArray(children).find(
    ({ props: { exp, otherwise } }) => exp || otherwise
  ) || <></>;

const When = ({ children, exp = false, otherwise = false }) =>
  exp === 0 ? <></> : (exp || otherwise) && children;
```

#### 使用例：

例えば、ロールごとに異なるコンポーネントを表示するパターンを考えてみよう。

```jsx
function UserAccess({ role }) {
  return (
    <Match>
      <When exp={role === 'admin'}>
        <AdminDashboard />
      </When>
      <When exp={role === 'editor'}>
        <EditorPanel />
      </When>
      <When exp={role === 'viewer'}>
        <ViewerContent />
      </When>
      <When otherwise>
        <GuestAccess />
      </When>
    </Match>
  );
}
```

このパターンなら、if文を並べる必要がなく、条件ごとにスッキリ整理できる。条件が増えても**ネストが深くならない**し、**読みやすさが保たれる**。

---

### SWRと`Match`と`When`の組み合わせ

例えば、`SWR`のデータ取得の状態に応じて異なる表示をする場合にも、`Match`と`When`はとても便利。

```jsx
import useSWR from 'swr'

function Profile() {
  const { data, error, isLoading } = useSWR('/api/user', fetcher)

  return (
    <Match>
      <When exp={error}>
        <div>failed to load</div>
      </When>
      <When exp={isLoading}>
        <div>loading...</div>
      </When>
      <When exp={data}>
        <div>hello {data.name}!</div>
      </When>
      <When otherwise>
        <div>no data available</div>
      </When>
    </Match>
  )
}
```

SWRの結果に応じて、必要なUIコンポーネントを簡単に切り替えることができる。複雑なif文や三項演算子を使うより、こちらの方が圧倒的にシンプル。

---

### Reactだけじゃない：JavaScript（TypeScript）での`match`と`when`

Reactで`Match`と`When`を使ってif文を駆逐したら、次はもっと広くJavaScriptの世界でも同じことをしたくならない？  
実は、`match`と`when`という関数を使えば、JavaScriptでもif文をもっとシンプルに整理できるんだ。

---

### `match` と `when` の実装

#### TypeScript版：

```ts
type When<T> = [boolean, () => T];

const is = (exp: boolean) =>
  <T>(t: () => T = () => true as T) =>
    (f: () => T = () => false as T) =>
      [f, t][Number(exp)]();

const match = <T>(l: When<T>[]) => (ow: () => T = () => undefined as unknown as T): T => {
  const tl = l.flatMap(([exp, fn]) => is(exp)(() => [fn])(() => []));
  return is(tl.length === 0)(ow)(tl[0]);
};

const when = <T>([exp, fn]: When<T>) => exp && fn();
```

#### JavaScript版：

```js
const is = (exp) => (t = () => true) => (f = () => false) => [f, t][Number(exp)]();

const match = (l) => (ow = () => undefined) => {
  const tl = l.flatMap(([exp, fn]) => is(exp)(() => [fn])(() => []));
  return is(tl.length === 0)(ow)(tl[0]);
};

const when = ([exp, fn]) => exp && fn();
```

この実装では、内部的に `is` 関数を使って、シンプルな条件分岐を表現している。if文や三項演算子をもっと整理された形で処理できるようにしているんだ。

---

### シンプルに使う例

この `match` と `when` を使って、条件分岐をもっと読みやすく、スッキリさせることができる。

#### `match` の例：

例えば、スコアに応じて評価を返すような条件分岐があるとする。この場合、`match` を使うことで、if文や三項演算子を使わずに、条件に応じた結果を返せる。

```ts
const score = 85;

const result = match([
  [score >= 90, () => "A"],
  [score >= 70, () => "B"],
  [score >= 50, () => "C"],
  [score < 50, () => "F"]
])(() => "Invalid score");

console.log(result);  // "B"
```

`match` 関数は、条件と処理をペアにしてリスト化することで、コードの可読性を保ちながら柔軟に条件を追加できる。

#### `when` の例：

もっとシンプルな1つの条件を評価したいときは、`when` を使って結果を返せる。

```ts
const score = 95;
const result = when([score >= 90, () => "A"])
console.log(result);  // "A"
```

このように、`when` は1つの条件に対して利用可能

---

### 実は思いつきで作った制御構造

ここまで話しておいてなんだけど、実はこの **`Match`と`When`**、そして **`match`と`when`**、完全に思いつきで作ったものなんだ。まだこれを使って大規模なプロジェクトを組んだわけじゃない。でも、試してみたら案外いけるんじゃないかなって思ったんだよ。

もしこの記事を読んで「これ、試してみようかな？」って思ってくれたら、僕たちは一緒に**if文駆逐計画**の先駆者になれるかもしれない。そう思うと、少しワクワクしない？

---

### より複雑なパターンマッチングへの道

ここまで紹介した `match` と `when` は、シンプルな条件分岐やパターンマッチングに適しているけど、もっと複雑なパターンやデータ構造に対してはどうするか？  
その場合には、さらに強力なパターンマッチングライブラリとして [ts-pattern](https://github.com/gvergnaud/ts-pattern) がある。  
これはTypeScript向けに設計されていて、型安全かつ強力なパターンマッチを実現できるライブラリだ。もし複雑な分岐に遭遇したら、ts-patternを使うことで、さらに柔軟に対応できるはず。


---

### まとめ：if文はロック。でも、少し肩の力を抜いてみよう

if文はロックだよ。無骨で力強く、コードを書く楽しさを教えてくれた。でも、今はもっと楽に、気楽にコードを書いていきたい。

**`Match`と`When`**、そして **`match`と`when`** を使えば、if文を駆逐して、もっとシンプルなコードを書ける。もしif文に疲れてきたなら、この方法を試してみてほしい。次のステップに進んでいこう。