{
  "id": 1279448,
  "title": "I Tried to Eliminate if. I Ended Up Putting match in My Language.",
  "url": "https://urgent.news/2026/08/16/i-tried-to-eliminate-if-i-ended-up-putting-match-in-my-language",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-08-16T13:53:16.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/kentaromorishita/i-tried-to-eliminate-if-i-ended-up-putting-match-in-my-language-41b6"
  },
  "original_language": "en",
  "account": "In 2024, I wrote an article on Qiita titled \"The Plan to Eradicate if Statements\", which initially sounded dangerous. However, my intention was not to eliminate the \"if\" keyword entirely. I simply wanted to avoid navigating through control flow when all I truly wanted to do was differentiate between cases. In TypeScript, this looked like this:\n\nlet label: string\nif (score === 90) {\nlabel = \"A\"\n} else if (score === 70) {\nlabel = \"B\"\n} else {\nlabel = \"C\"\n}\n\nWhile nothing is inherently wrong with this approach, my main concern was the act of continually assigning values into \"label\". I preferred the classification of \"score\" into a \"label\" instead. This led me to favor ternary expressions:\n\nconst label = score === 90 ? \"A\" : score === 70 ? \"B\" : \"C\"\n\nNevertheless, as the cases multiplied, it became cumbersome to read. Consequently, I began creating my own \"match\"- and \"when\"-like abstractions using TypeScript. In retrospect, the moment I started mimicking language features with a library may have been a cautionary sign. Within Seseragi, it became simply \"match\". I preferred Seseragi's match not just because it was convenient, but because it functioned as an expression from the outset. No temporary variable was needed to store the result— the entire function read as \"classify a score into a String\".\n\nADTs (Algebraic Data Types) made Seseragi's match even more appealing. With numeric conditions alone, TypeScript was sufficient. However, Seseragi's match truly shined when the value itself was an algebraic data type. For instance:\n\ntype Session = | Loading | Guest | LoggedIn String | Failed String\nfn label session: Session -> String = match session {\nLoading -> \"Loading...\"\nGuest -> \"Guest\"\nLoggedIn name -> `Hello, $name`\nFailed message -> `Error: $message`\n}\n\nThe type defines the possible states, and match handles those exact shapes. This made the code much easier to read than dealing with several booleans to figure out the application's state. Additionally, if I added a constructor without handling it, the compiler would turn it into an exhaustiveness problem. This approach closely aligned with what I was originally striving for when building match-like libraries in TypeScript.\n\nI later realized that I had been trying to make branching behave more like producing a value in TypeScript. Now, I have a language with \"match\" in it. My philosophy didn't change dramatically; I just continued refining it until something I had forced a library to imitate became an ordinary language feature. As a result, Seseragi still includes \"if\" statements. The eradication attempt did not succeed. I believe this outcome was ultimately beneficial.",
  "summary": "In 2024, I wrote a Qiita article whose title roughly translates to \"The Plan to Eradicate if Statements.\" https://qiita.com/KentaroMorishita/items/6329d20fbc6f98f72864 Looking at the title now, it sounds a little dangerous. But I didn't literally want to remove if from the world. What bothered me was having to chase control flow when all I really wanted to do was distinguish between cases . I was…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}