Conditional Assignment vs If Else Statement
Ternary-style conditional assignment versus the full if/else block — when each one earns its place in your code, and which one to reach for by default.
The short answer
Conditional Assignment over If Else Statement for most cases. When the entire job is "set this variable to one of two values," conditional assignment says exactly that in one expression.
- Pick Conditional Assignment if picking one of two values for a single variable or return — a ternary, null-coalescing, or guard expression makes the intent obvious and keeps it an expression
- Pick If Else Statement if the branches do genuinely different work — multiple statements, side effects, early returns, logging — where forcing it into one expression would be a crime
- Also consider: Readability is the real metric, not line count. A nested ternary three levels deep is worse than the dumbest if/else. Pick the form that reads in one pass.
— Nice Pick, opinionated tool recommendations
What they actually are
Neither of these is a product, a library, or a thing you install — they are two ways to express a fork in the road. Conditional assignment is an expression that resolves to a value: a ternary (cond ? a : b), null-coalescing (x ?? y), Python's a if cond else b, or Kotlin's if-as-expression. It hands you a value and you bind it. The if/else statement is control flow: it runs one block or another and produces nothing on its own. The distinction is expression versus statement, and it is the whole ballgame. Conditional assignment composes — you can drop it inside a function call, an array literal, a JSX prop. A statement cannot. People treat this as a style war. It is not. It is a question of whether your fork produces a value or performs an action, and the language usually already told you the answer.
Where conditional assignment wins
The moment your code is 'set status to active or inactive based on a flag,' the if/else block is pure ceremony. You declare the variable, leave it uninitialized or mutable, write four lines, and assign the same target in two places — now a linter has to trust you set it on every path. The ternary states the intent in one breath: status = flag ? 'active' : 'inactive'. It keeps the binding immutable, keeps the assignment target named once, and drops cleanly into a return, a config object, or a template. It also resists rot: nobody sneaks a console.log or a metrics call into a branch of an expression, because there are no branches to sneak into. For value selection — defaults, fallbacks, normalizing one of two inputs — this is the correct tool and the if/else is just a longer way to be wrong.
Where if/else earns it back
Conditional assignment collapses the instant the branches stop being values. Two statements per side, an early return, a thrown error, a log line, an await with cleanup — cram any of that into a ternary and you get an unreadable comma-operator horror or an immediately-invoked arrow function that fools nobody. This is where the if/else is not a compromise, it is correct. It gives each branch a real scope to do real work. The failure mode of the ternary crowd is nesting: a ? b : c ? d : e ? f : g is a decision tree pretending to be a line, and it is worse than the most verbose block. If you find yourself reaching for a second colon, stop and write the if/else — or a lookup table. The statement also wins when the condition guards a side effect that produces no value at all, because then there is nothing to assign.
The verdict, sharpened
Stop arguing this in the abstract and ask one question: does this fork produce a value, or perform an action? Value — conditional assignment, every time; the if/else block is line-count theater that mutates where it should bind and repeats the target where it should name it once. Action — if/else, and don't let a ternary zealot talk you into an IIFE. The trap on both sides is the same: complexity smuggled into the wrong shape. A nested ternary is a flowchart cosplaying as an expression; a five-line if/else around a single assignment is a paragraph where a phrase would do. Default to conditional assignment for selection because it is honest about what it does and resists later abuse. Escalate to if/else the moment branches diverge in behavior. The good engineer doesn't have a favorite — they read the fork and pick the shape that matches it.
Quick Comparison
| Factor | Conditional Assignment | If Else Statement |
|---|---|---|
| Produces a value | Yes — it is an expression you can compose anywhere | No — it is control flow that runs blocks |
| Multi-statement / side-effect branches | Forces ugly IIFE or comma hacks | Native — each branch gets a real scope |
| Immutability of the bound target | Binds once, stays const | Usually needs a mutable, two-site assignment |
| Readability under deep nesting | Degrades fast — nested ternaries are a flowchart in disguise | Stays legible with else-if chains |
| Default for simple value selection | One line, intent-obvious, rot-resistant | Ceremony — four lines to say one thing |
The Verdict
Use Conditional Assignment if: You are picking one of two values for a single variable or return — a ternary, null-coalescing, or guard expression makes the intent obvious and keeps it an expression.
Use If Else Statement if: The branches do genuinely different work — multiple statements, side effects, early returns, logging — where forcing it into one expression would be a crime.
Consider: Readability is the real metric, not line count. A nested ternary three levels deep is worse than the dumbest if/else. Pick the form that reads in one pass.
When the entire job is "set this variable to one of two values," conditional assignment says exactly that in one expression. The if/else block scatters the same intent across five lines, repeats the assignment target twice, and invites someone to wedge an unrelated side effect into a branch later. Default to conditional assignment for value selection; reach for if/else only when branches actually do different work.
Related Comparisons
Disagree? nice@nicepick.dev