Three operands, a question mark, a colon: the only construct in the language taking three elements, hence its name. It exists to choose a value, not to run code.
Definition
The ternary operator evaluates a condition, then returns the value placed before the colon when it is true, and the one placed after when it is false. Its shape never changes.
const age = 20;
const status = age >= 18 ? "adult" : "minor";
console.log(status); // "adult"
// The same result with if and else
let statusAgain;
if (age >= 18) statusAgain = "adult";
else statusAgain = "minor";Both forms produce the same result, but the first fits on one line and allows const, which the second forbids since the variable has to be declared before being filled.
An expression, not a statement
That is the whole difference with if, and the reason it exists. An if runs code; the ternary produces a value, so it fits anywhere a value is expected.
const n = 3;
// Inside a text
console.log(`There ${n > 1 ? "are" : "is"} ${n}`);
// Inside a function return
const label = (v) => v > 0 ? "positive" : "negative";
// Inside an array transformation
console.log([1, 2].map((x) => x % 2 ? "odd" : "even"));None of those three places accepts an if. That explains its heavy presence in interface components, where a label or a class often has to be picked in the middle of the markup.
The line not to cross
The operator nests, and that is exactly where code turns unreadable. Two levels still pass, beyond that reading becomes an exercise in patience.
const n = 4, subscribed = true, yearly = false;
// Acceptable
const label = n === 0 ? "none" : n === 1 ? "one" : "several";
// Avoid: three levels and a compound condition
const price = subscribed ? (yearly ? 199 : 19) : (yearly ? 99 : 9);
console.log(label, price); // several 19Past two branches, a switch, a lookup object or a named function give the reader back what nesting takes away. Saving lines never justifies losing clarity.
Do not confuse it with Nullish coalescing (??). The ternary tests a condition and fires on any Truthy and falsy value; the ?? operator only reacts to null and undefined, which preserves zero and the empty string.
Frequently asked questions
Can it be used without keeping the result?
Technically yes, but it misses the point. A ternary whose value is thrown away acts as a disguised conditional statement, a role that belongs to if. Linters flag it, and rightly so: reading gets heavier for no gain at all.
How do I handle more than two cases?
A lookup object is often the most readable answer: keys carry the cases, values carry the results, and a fallback covers unknown inputs. A switch also fits as soon as an action, and not merely a value, depends on the case.
Are parentheses required around the condition?
They are not mandatory, but they prevent precedence surprises when the condition contains an addition or a concatenation. A good habit is to wrap the whole ternary in parentheses as soon as it sits inside another expression.