{"id":14978271,"url":"https://github.com/getify/eslint-plugin-proper-ternary","last_synced_at":"2025-04-30T21:24:31.502Z","repository":{"id":52528221,"uuid":"177423398","full_name":"getify/eslint-plugin-proper-ternary","owner":"getify","description":"ESLint rules to ensure proper usage of ternary/conditional expressions","archived":false,"fork":false,"pushed_at":"2021-04-26T23:55:28.000Z","size":47,"stargazers_count":96,"open_issues_count":5,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-22T07:12:49.413Z","etag":null,"topics":["eslint","eslint-plugin","eslint-rules","ternary"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/getify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["getify"],"patreon":"getify","custom":["https://www.paypal.com/paypalme2/getify","https://www.blockchain.com/btc/payment_request?address=3GrZuzooWAAjufEydb7c8MrUYznCiHHT9U\u0026message=getify+Support+Donation"]}},"created_at":"2019-03-24T14:08:58.000Z","updated_at":"2024-07-08T14:31:05.000Z","dependencies_parsed_at":"2022-08-22T01:31:08.175Z","dependency_job_id":null,"html_url":"https://github.com/getify/eslint-plugin-proper-ternary","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getify%2Feslint-plugin-proper-ternary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getify%2Feslint-plugin-proper-ternary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getify%2Feslint-plugin-proper-ternary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getify%2Feslint-plugin-proper-ternary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getify","download_url":"https://codeload.github.com/getify/eslint-plugin-proper-ternary/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251783977,"owners_count":21643192,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eslint","eslint-plugin","eslint-rules","ternary"],"created_at":"2024-09-24T13:57:15.695Z","updated_at":"2025-04-30T21:24:31.454Z","avatar_url":"https://github.com/getify.png","language":"JavaScript","funding_links":["https://github.com/sponsors/getify","https://patreon.com/getify","https://www.paypal.com/paypalme2/getify","https://www.blockchain.com/btc/payment_request?address=3GrZuzooWAAjufEydb7c8MrUYznCiHHT9U\u0026message=getify+Support+Donation"],"categories":[],"sub_categories":[],"readme":"# ESLint Plugin: proper-ternary\n\n[![Build Status](https://travis-ci.org/getify/eslint-plugin-proper-ternary.svg?branch=master)](https://travis-ci.org/getify/eslint-plugin-proper-ternary)\n[![npm Module](https://badge.fury.io/js/%40getify%2Feslint-plugin-proper-ternary.svg)](https://www.npmjs.org/package/@getify/eslint-plugin-proper-ternary)\n[![Dependencies](https://david-dm.org/getify/eslint-plugin-proper-ternary.svg)](https://david-dm.org/getify/eslint-plugin-proper-ternary)\n[![devDependencies](https://david-dm.org/getify/eslint-plugin-proper-ternary/dev-status.svg)](https://david-dm.org/getify/eslint-plugin-proper-ternary?type=dev)\n[![Coverage Status](https://coveralls.io/repos/github/getify/eslint-plugin-proper-ternary/badge.svg?branch=master)](https://coveralls.io/github/getify/eslint-plugin-proper-ternary?branch=master)\n\n## Overview\n\nThe **proper-ternary** ESLint plugin provides rules that control the definitions of `? :` conditional expressions (aka, \"ternary expressions\"), restricting them to a narrower and more proper/readable form.\n\nThe rules defined in this plugin:\n\n* [`\"nested\"`](#rule-nested): controls the nesting of `? :` ternary expressions.\n\n* [`\"parens\"`](#rule-parens): requires surrounding `( .. )` parentheses around specific kinds of expressions in ternary expression clauses.\n\n* [`\"where\"`](#rule-where): restricts where in program structure ternary expressions can be used: forbidding them as standalone statements, in object properties, as arguments, etc.\n\n## Enabling The Plugin\n\nTo use **proper-ternary**, load it as a plugin into ESLint and configure the rules as desired.\n\n### `extends`\n\nIf you'd like to use the **proper-ternary** plugin in a recommended configuration preset, you can add the plugin in the `extends` clause of your ESLint configuration, and pick a preset by name:\n\n```js\n\"extends\": [\n    // ..\n    \"plugin:@getify/proper-ternary/CONFIG-PRESET-NAME\",\n    // ..\n]\n```\n\n**Note:** All included configuration presets not only define specific rule configurations but also automatically load the plugin itself, so you *don't* need to list **proper-ternary** in the `plugins` clause.\n\nThe available configuration presets to choose from:\n\n* `getify-says`: This is my personal configuration. See the [preset definition](/lib/index.js#L5-L12).\n\n* ..TBA..\n\nIt's important to note that you can still override any of the preset rule definitions in your configuration. Think of these presets as convenience \"defaults\" that can still be customized.\n\n### `.eslintrc.json`\n\nTo load the plugin and enable its rules via a local or global `.eslintrc.json` configuration file:\n\n```json\n\"plugins\": [\n    \"@getify/proper-ternary\"\n],\n\"rules\": {\n    \"@getify/proper-ternary/nested\": \"error\",\n    \"@getify/proper-ternary/parens\": \"error\",\n    \"@getify/proper-ternary/where\": \"error\"\n}\n```\n\n### `package.json`\n\nTo load the plugin and enable its rules via a project's `package.json`:\n\n```json\n\"eslintConfig\": {\n    \"plugins\": [\n        \"@getify/proper-ternary\"\n    ],\n    \"rules\": {\n        \"@getify/proper-ternary/nested\": \"error\",\n        \"@getify/proper-ternary/parens\": \"error\",\n        \"@getify/proper-ternary/where\": \"error\"\n    }\n}\n```\n\n### ESLint CLI parameters\n\nTo load the plugin and enable its rules via ESLint CLI parameters, use `--plugin` and `--rule` flags:\n\n```cmd\neslint .. --plugin='@getify/proper-ternary' --rule='@getify/proper-ternary/nested: error' ..\n```\n\n```cmd\neslint .. --plugin='@getify/proper-ternary' --rule='@getify/proper-ternary/parens: error' ..\n```\n\n```cmd\neslint .. --plugin='@getify/proper-ternary' --rule='@getify/proper-ternary/where: error' ..\n```\n\n### ESLint Node API\n\nTo use this plugin in Node.js with the ESLint API, require the npm module, and then (for example) pass the rule's definition to `Linter#defineRule(..)`, similar to:\n\n```js\nvar properTernary = require(\"@getify/eslint-plugin-proper-ternary\");\n\n// ..\n\nvar eslinter = new (require(\"eslint\").Linter)();\n\neslinter.defineRule(\"@getify/proper-ternary/nested\",properTernary.rules.nested);\n\neslinter.defineRule(\"@getify/proper-ternary/parens\",properTernary.rules.parens);\n\neslinter.defineRule(\"@getify/proper-ternary/where\",properTernary.rules.where);\n```\n\nThen lint some code like this:\n\n```js\neslinter.verify(\".. some code ..\",{\n    rules: {\n        \"@getify/proper-ternary/nested\": \"error\",\n        \"@getify/proper-ternary/parens\": \"error\",\n        \"@getify/proper-ternary/where\": \"error\"\n    }\n});\n```\n\n### Inline Comments\n\nOnce the plugin is loaded, the rule can be configured using inline code comments if desired, such as:\n\n```js\n/* eslint \"@getify/proper-ternary/nested\": \"error\" */\n```\n\n```js\n/* eslint \"@getify/proper-ternary/parens\": \"error\" */\n```\n\n```js\n/* eslint \"@getify/proper-ternary/where\": \"error\" */\n```\n\n## Rule: `\"nested\"`\n\nThe **proper-ternary**/*nested* rule controls the nesting of `? :` ternary expressions.\n\nTo turn this rule on:\n\n```json\n\"@getify/proper-ternary/nested\": \"error\"\n```\n\nThe main purpose of this rule is to avoid readability harm for `? :` ternary expressions with confusing nesting of other ternary expressions. By forbidding confusing nesting, the reader can more clearly understand what the ternary will result in.\n\nFor example:\n\n```js\nvar name = userData ? userData.name : \"-empty-\";\n```\n\nThis ternary expression doesn't have any other ternary expression nested in it. It's much clearer to figure out what its behavior will be. Therefore, the **proper-ternary**/*nested* rule would not report any errors.\n\nBy default, ternary expression nesting is forbidden **in all three ternary expression clauses**, and nesting depth is furthermore limited to one level. As such, this rule *would* default to **reporting errors** for each of these statements:\n\n```js\nvar name =\n    (typeof isLoggedIn == \"function\" ? isLoggedIn() : false)\n        ? userData.name\n        : \"-empty-\";\n\nvar email =\n    userData != null\n        ? (userData.email != \"\" ? userData.email : \"nobody@email.tld\")\n        : \"-empty-\";\n\nvar accountType =\n    userData.type == 1 ? \"admin\" :\n    userData.type == 2 ? \"manager\" :\n    userData.type == 3 ? \"vendor\" :\n    \"customer\";\n```\n\nThe `name` assignment statement has a ternary expression nested inside the \"test\" clause of the outer ternary expression. The `email` assignment statement has a ternary expression nested inside the \"then\" (aka \"consequent\") clause of the outer ternary expression. The `accountType` assignment statement nests ternary expressions in the \"else\" (aka \"alternate\") clauses of their outer ternary expressions. Also, the `accountType` assignment statement has **two levels of nesting**, whereas the `name` and `email` assignment statements each have ternary expressions with **one level of nesting**.\n\nTo allow nesting in a specific clause (`\"test\"`, `\"then\"`, and `\"else\"`), that clause type must be configured on. To allow nesting beyond one level, the `\"depth\"` configuration must be increased.\n\n### Rule Configuration\n\nThe **proper-ternary**/*nested* rule can be configured with various combinations of these modes:\n\n* [`\"test\"`](#rule-nested-configuration-clauses) (default: `false`) allows a ternary expression nested in the \"test\" clause of another ternary expression.\n\n* [`\"then\"`](#rule-nested-configuration-clauses) (default: `false`) allows a ternary expression nested in the \"then\" (aka, \"consequent\") clause of another ternary expression.\n\n* [`\"else\"`](#rule-nested-configuration-clauses) (default: `false`) allows a ternary expression nested in the \"else\" (aka, \"alternate\") clause of another ternary expression.\n\n* [`\"depth\"`](#rule-nested-configuration-depth) (default: `1`) controls how many levels of nesting of ternary expressions are allowed. To effectively use this option, you must also enable at least one of the `\"test\"` / `\"then\"` / `\"else\"` clause modes.\n\n**Note:** This rule does not consider stylistic readability affordances like whitespace or parentheses (see [`\"parens\"` rule](#rule-parens)), only structural questions of nesting.\n\n#### Rule `\"nested\"` Configuration: Clauses\n\nTo configure the `\"test\"`, `\"then\"`, or `\"else\"` rule modes (each default: `false`):\n\n```json\n\"@getify/proper-ternary/nested\": [ \"error\", { \"test\": true, \"then\": true, \"else\": true }\n```\n\nEach clause must be explicitly enabled for nested ternary expressions to be allowed there. Leaving all three clause types disabled effectively disables all ternary expression nesting.\n\n##### `\"test\"` Nesting\n\nIf `\"test\"` mode is enabled, nesting a ternary expression in the *test* clause looks like this:\n\n```js\nvar name =\n    (typeof isLoggedIn == \"function\" ? isLoggedIn() : false)\n        ? userData.name\n        : \"-empty-\";\n```\n\nThis form is equivalent to the fairly awkward:\n\n```js\nvar name;\nif (\n    (typeof isLoggedIn == \"function\" || false) \u0026\u0026 isLoggedIn()\n) {\n    name = userData.name;\n}\nelse {\n    name = \"-empty-\";\n}\n```\n\nThe awkward/confusing boolean logic in this `if..else` equivalent form suggests a simpler way to structure the logic:\n\n```js\nvar name;\nif (typeof isLoggedIn == \"function\" \u0026\u0026 isLoggedIn()) {\n    name = userData.name;\n}\nelse {\n    name = \"-empty-\";\n}\n\n```\n\nAnd while that logic certainly makes more sense, it illustrates why nesting ternary expressions in the *test* clause is rarer, as there's basically no need for the extra conditional in the first place:\n\n```js\nvar name =\n    (typeof isLoggedIn == \"function\" \u0026\u0026 isLoggedIn())\n        ? userData.name\n        : \"-empty-\";\n```\n\nThe main reason to prefer the ternary expression form in this case, over the `if..else` form, is that it's more clear in this latter form that there's a single variable `name` being assigned one of two values. With the `if..else` form, there are two separate assignments, so this detail is slightly less obvious.\n\n##### `\"then\"` Nesting\n\nIf the `\"then\"` mode is enabled, the more common nesting of a ternary expression in the *then* clause of another ternary expression looks like:\n\n```js\nvar email =\n    userData != null\n        ? (userData.email != \"\" ? userData.email : \"nobody@email.tld\")\n        : \"-empty-\";\n```\n\nIn this form, it's clear that there's a single variable `email` being assigned. The `if..else` equivalent:\n\n```js\nvar email;\nif (userData != null) {\n    if (userData.email != \"\") {\n        email = userData.email;\n    }\n    else {\n        email = \"nobody@email.tld\";\n    }\n}\nelse {\n    email = \"-empty-\";\n}\n```\n\nIn this form, the single assignment (with one of three values) is a little less obvious. Generally, the former ternary expression form would be preferred as a bit more readable in cases like this.\n\n##### `\"else\"` Nesting\n\nIf the `\"else\"` mode is enabled, nesting a ternary expression in the *else* clause of another ternary expression is perhaps the most readable of the ternary expression nesting variations:\n\n```js\nvar accountType =\n    userData.type == 1 ? \"admin\"   :\n    userData.type == 2 ? \"manager\" :\n    userData.type == 3 ? \"vendor\"  :\n    \"customer\";\n```\n\nIn this form, it's fairly clear that there's a single variable `accountType` being assigned one of four values, based on three specific comparisons, with the fourth value being the default \"else\" value.\n\nThe more verbose `if..else if` equivalent:\n\n```js\nvar accountType;\nif (userData.type == 1) {\n    accountType = \"admin\";\n}\nelse if (userData.type == 2) {\n    accountType = \"manager\";\n}\nelse if (userData.type == 3) {\n    accountType = \"vendor\";\n}\nelse {\n    accountType = \"customer\";\n}\n```\n\nThe single variable (`accountType`) assignment is a little less obvious in this form, and there's more syntactic noise just to accomplish the same result. So, the ternary expression form may be a bit more preferable.\n\n#### Rule `\"nested\"` Configuration: `\"depth\"`\n\nTo configure this rule mode (default: `1`):\n\n```json\n\"@getify/proper-ternary/nested\": [ \"error\", { \"depth\": 1 } ]\n```\n\nIf any of the [`\"test\"` / `\"then\"` / `\"else\"` modes](#rule-nested-configuration-clauses) are enabled, you can also control how many levels of ternary expression nesting are allowed with the `\"depth\"` setting.\n\nFor example, by default this rule mode would not report any errors for this ternary expression:\n\n```js\nvar accountType =\n    userData.type == 1 ? \"admin\"   :\n    userData.type == 2 ? \"manager\" :\n    \"customer\";\n```\n\nThe nesting level is `1` (inside the second/outermost ternary expression).\n\nBy contrast, this rule mode *would* by default report errors for:\n\n```js\nvar accountType =\n    userData.type == 1 ? \"admin\"   :\n    userData.type == 2 ? \"manager\" :\n    userData.type == 3 ? \"vendor\"  :\n    \"customer\";\n```\n\nHere, the nesting level is `2` (inside the third/outermost ternary expression), so the default nesting level of `1` would cause an error to be reported for the `userData.type == 3 ? ..` ternary expression.\n\n## Rule: `\"parens\"`\n\nThe **proper-ternary**/*parens* rule requires `( .. )` parentheses surrounding various expression types when they appear in any clause of a ternary expression.\n\nTo turn this rule on:\n\n```json\n\"@getify/proper-ternary/parens\": \"error\"\n```\n\nThe main purpose of this rule is to avoid readability harm for `? :` ternary expressions by requiring disambiguating `( .. )` around any clause's expression if that expression's boundary isn't obvious, such as operator associativity or precedence, for example.\n\nFor example:\n\n```js\nvar total = 1 + base ? base * 2 : base * 3;\n```\n\nWithout looking up operator precedence, a reader may not be confident whether the `1 + ` part belongs to the *test* clause of the ternary, or is added after the ternary is resolved. In other words, that example could reasonably be assumed as either of these:\n\n```js\nvar total = (1 + base) ? base * 2 : base * 3;\n\n// OR\n\nvar total = 1 + (base ? base * 2 : base * 3);\n```\n\nWhich is it? Because of operator precedence, it's the first one (`(1 + base) ? ..`). But this kind of ambiguity can really harm readability. Moreover, when quickly scanning the code, the `base * 2` and `base * 3` expressions can obscure the location of the `?` and `:` operators and thus the clause boundaries.\n\nConsider a more readable alternative:\n\n```js\nvar total = (1 + base) ? (base * 2) : (base * 3);\n```\n\nYes, the `( .. )` are \"unnecessary\", but they certainly eliminate the ambiguity from such examples. Readability affordances such as this should be favored.\n\nThe default behavior of this rule is aggressive, in that it requires parentheses around **all clause expression types** (except simple identifiers/literals); it will **report errors** for each of these ternary expression clauses here:\n\n```js\nvar total = base \u003e 1 ? base * 2 : base * 3;\n```\n\nThe `base \u003e 1` expression is a *comparison* expression, and can be allowed by disabling the [`\"comparison\"`](#rule-parens-configuration-comparison) mode. The `base * 2` and `base * 3` expressions are *complex*; there is **no mode in this rule** to disable reporting errors for them.\n\n### Rule Configuration\n\nThe **proper-ternary**/*parens* rule can be configured with any combination of these modes, applied to expressions in **any of the clauses** of a ternary expression:\n\n* [`\"ternary\"`](#rule-parens-configuration-ternary) (default: `true`) requires a nested ternary expression to have `( .. )` surrounding it.\n\n* [`\"comparison\"`](#rule-parens-configuration-comparison) (default: `true`) requires a comparison expression (ie, `x == y`, `x \u003e y`, etc) to have `( .. )` surrounding it.\n\n* [`\"logical\"`](#rule-parens-configuration-logical) (default: `true`) requires a logical expression (ie, `x \u0026\u0026 y`, `!x`, etc) to have `( .. )` surrounding it.\n\n* [`\"call\"`](#rule-parens-configuration-call) (default: `true`) requires a call expression (ie, `foo()`, `new Foo()`, etc) to have `( .. )` surrounding it.\n\n* [`\"object\"`](#rule-parens-configuration-object) (default: `true`) requires an object or array literal (ie, `{x:1}`, `[1,2]`, etc) to have `( .. )` surrounding it.\n\n* [`\"simple\"`](#rule-parens-configuration-simple) (**default: `false`**) requires a simple expression (ie, `x`, `x.y`, `42`, etc) to have `( .. )` surrounding it. It's likely you'll want to keep this mode disabled (default).\n\n**Note:** Any expression not covered by these modes, such as `x + y`, is considered a *complex* expression. If this rule is enabled, complex expressions always require `( .. )` surrounding them; there is no `\"complex\"` mode to disable them. Reasoning: if you feel that `x + y * z` is a sufficient expression to not need `( .. )`, then you almost certainly would be inclined to disable all the other above modes too, in which case you should just disable the rule entirely.\n\n#### Rule `\"nested\"` Configuration: Ternary\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/parens\": [ \"error\", { \"ternary\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar x = y ? z : w ? u : v;\n```\n\nTo avoid this error, use `( .. )` around the nested ternary:\n\n```js\nvar x = y ? z : (w ? u : v);\n```\n\n#### Rule `\"nested\"` Configuration: Comparison\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/parens\": [ \"error\", { \"comparison\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar x = y \u003e 3 ? y : z;\n```\n\nTo avoid this error, use `( .. )` around the comparison expression:\n\n```js\nvar x = (y \u003e 3) ? y : z;\n```\n\n#### Rule `\"nested\"` Configuration: Logical\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/parens\": [ \"error\", { \"logical\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar x = y \u0026\u0026 z ? y : z;\n```\n\nTo avoid this error, use `( .. )` around the logical expression:\n\n```js\nvar x = (y \u0026\u0026 z) ? y : z;\n```\n\n#### Rule `\"nested\"` Configuration: Call\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/parens\": [ \"error\", { \"call\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar x = y ? foo(y,z) : z;\n```\n\nTo avoid this error, use `( .. )` around the call expression:\n\n```js\nvar x = y ? ( foo(y,z) ) : z;\n```\n\n#### Rule `\"nested\"` Configuration: Object\n\n**Note:** This rule mode applies to both array literals (`[1,2]`) and object literals (`{x:1}`).\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/parens\": [ \"error\", { \"object\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar x = y ? [y,z] : z;\n```\n\nTo avoid this error, use `( .. )` around the array or object expression:\n\n```js\nvar x = y ? ( [y,z] ) : z;\n```\n\n#### Rule `\"nested\"` Configuration: Simple\n\n**Note:** It's very likely that you'll want to keep this mode off (default), as it's unlikely that you'll want to require `( .. )` around even simple identifiers and primitive literals.\n\nTo configure this rule mode **on** (**off** by default):\n\n```json\n\"@getify/proper-ternary/parens\": [ \"error\", { \"simple\": true } ]\n```\n\nIf this mode is on, it will report errors for each clause:\n\n```js\nvar x = y ? w.u : 42;\n```\n\nTo avoid these errors, use `( .. )` around each ternary clause's expression:\n\n```js\nvar x = (y) ? (w.u) : (42);\n```\n\n## Rule: `\"where\"`\n\nThe **proper-ternary**/*where* rule restricts where in program structure ternary expressions can be used.\n\nTo turn this rule on:\n\n```json\n\"@getify/proper-ternary/where\": \"error\"\n```\n\nThe main purpose of this rule is to avoid readability harm for the program when `? :` ternary expressions are misused. By restricting ternary expressions to certain usages, the ternary-forbidden usages are structured using more appropriate syntax/logic.\n\nFor example, some strongly feel ternary expressions should only be used as expressions (meaning conditionally selecting a value) and not as standalone statements like:\n\n```js\n(isLoggedIn(user) \u0026\u0026 user.admin)\n    ? renderAdminHeader()\n    : renderBasicHeader();\n```\n\nThis construct can be confusing to the reader, as it's easy to miss side-effects in either the *then* or *else* clause. A more preferred approach is to use a standalone `if..else` statement:\n\n```js\nif (isLoggedIn(user) \u0026\u0026 user.admin) {\n    renderAdminHeader();\n}\nelse {\n    renderBasicHeader();\n}\n```\n\nThis scenario is exactly what the `if..else` statement is best at; abusing a ternary expression to save a few characters is not helpful for readability.\n\nAnother example:\n\n```js\nvar loginRecord = {\n    name: userData.name,\n    accountType: (\n        userData.type == 1 ? \"admin\"   :\n        userData.type == 2 ? \"manager\" :\n        userData.type == 3 ? \"vendor\"  :\n        \"customer\"\n    )\n};\n```\n\nHere a ternary is being used inside an object literal, but a perhaps more readable approach would be to first choose the value via a variable assignment:\n\n```js\nvar accountType =\n    userData.type == 1 ? \"admin\"   :\n    userData.type == 2 ? \"manager\" :\n    userData.type == 3 ? \"vendor\"  :\n    \"customer\";\n\nvar loginRecord = {\n    name: userData.name,\n    accountType\n};\n```\n\nA similar situation arises with arguments to function calls: because arguments generally don't have obvious names at the call-site, using a ternary expression as an argument can be less readable if for no other reason than lack of any semantic name to describe the value selection. It's often better to perform the ternary conditional value selection in an assignment first, then pass that named variable as the argument.\n\nIt can also be harder to read code when a ternary expression is a sub-expression in another expression, such as the unary `!` negation expression below:\n\n```js\nvar isAllowed = !(\n    (userSession != null)\n        ? userSession.user.accountType == \"customer\"\n        : defaultAccountType == \"vendor\"\n);\n```\n\nThe indirect negation logic here is more confusing to the reader. A better approach:\n\n```js\nvar basicAccountType =\n    (userSession != null)\n        ? userSession.user.accountType == \"customer\"\n        : defaultAccountType == \"vendor\";\n\nvar isAllowed = !basicAccountType;\n```\n\nBy semantically naming the result of the ternary decision (`basicAccountType`), the negation is clearer to understand.\n\nOf course, in this example, the ternary itself isn't strictly necessary, as the logic could have been structured as:\n\n```js\nvar basicAccountType = (\n    (userSession != null \u0026\u0026 userSession.user.accountType == \"customer\") ||\n    (defaultAccountType == \"vendor\")\n);\n\nvar isAllowed = !basicAccountType;\n```\n\nSome will prefer the ternary version and others will prefer this non-ternary form.\n\n### Rule Configuration\n\nThe **proper-ternary**/*where* rule can be configured with any combination of these modes:\n\n* [`\"statement\"`](#rule-where-configuration-statement) (default: `true`) forbids a standalone ternary expression statement.\n\n* [`\"property\"`](#rule-where-configuration-property) (default: `true`) forbids a ternary expression in an object literal property assignment or array literal position assignment.\n\n* [`\"argument\"`](#rule-where-configuration-argument) (default: `true`) forbids a ternary expression as an argument to a function call.\n\n* [`\"return\"`](#rule-where-configuration-return) (default: `true`) forbids a ternary expression in a `return` statement of a function, as well as the concise return of an `=\u003e` arrow function.\n\n* [`\"default\"`](#rule-where-configuration-default) (default: `true`) forbids a ternary expression in a default value expression (function parameters and destructuring patterns).\n\n* [`\"sub\"`](#rule-where-configuration-sub) (default: `true`) forbids a ternary expression as a sub-expression of a unary/binary operator expression (ie, `1 + (x ? y : z)`).\n\n   **Note:** This rule mode does not control ternary expressions nested in other ternary expressions. For that, use the [`\"nested\"` rule](#rule-nested).\n\n* [`\"assignment\"`](#rule-where-configuration-assignment) (default: **`false`**) forbids a ternary expression in assignment statements (using the `=` operator).\n\n   **Note:** Unlike the other rule modes here, this mode is turned off by default, because it's unlikely that you'll want to disable ternary expressions in assignment expressions (ie, `x = y ? z : w`), as this is basically where they're most naturally useful. It's included for completeness sake, but if you're inclined to turn this rule mode on, you perhaps might just consider disabling all ternary expressions with the built-in [\"no-ternary\" rule](https://eslint.org/docs/rules/no-ternary).\n\n#### Rule `\"where\"` Configuration: Statement\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/where\": [ \"error\", { \"statement\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\n(isLoggedIn(user) \u0026\u0026 user.admin)\n    ? renderAdminHeader()\n    : renderBasicHeader();\n```\n\nTo avoid this error, use an `if..else` statement instead:\n\n```js\nif (isLoggedIn(user) \u0026\u0026 user.admin) {\n    renderAdminHeader();\n}\nelse {\n    renderBasicHeader();\n}\n```\n\n#### Rule `\"where\"` Configuration: Property\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/where\": [ \"error\", { \"property\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar loginRecord = {\n    name: userData.name,\n    accountType: (\n        userData.type == 1 ? \"admin\"   :\n        userData.type == 2 ? \"manager\" :\n        userData.type == 3 ? \"vendor\"  :\n        \"customer\"\n    )\n};\n```\n\nTo avoid this error, use an `if..else` statement instead:\n\n```js\nvar accountType =\n    userData.type == 1 ? \"admin\"   :\n    userData.type == 2 ? \"manager\" :\n    userData.type == 3 ? \"vendor\"  :\n    \"customer\";\n\nvar loginRecord = {\n    name: userData.name,\n    accountType\n};\n```\n\n#### Rule `\"where\"` Configuration: Property\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/where\": [ \"error\", { \"property\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar loginRecord = {\n    name: userData.name,\n    accountType: (\n        userData.type == 1 ? \"admin\"   :\n        userData.type == 2 ? \"manager\" :\n        userData.type == 3 ? \"vendor\"  :\n        \"customer\"\n    )\n};\n```\n\nTo avoid this error, use an `if..else` statement instead:\n\n```js\nvar accountType =\n    userData.type == 1 ? \"admin\"   :\n    userData.type == 2 ? \"manager\" :\n    userData.type == 3 ? \"vendor\"  :\n    \"customer\";\n\nvar loginRecord = {\n    name: userData.name,\n    accountType\n};\n```\n\n#### Rule `\"where\"` Configuration: Argument\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/where\": [ \"error\", { \"argument\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\ncheckAccount(\n    (isLoggedIn(user) \u0026\u0026 user.admin) ? user : defaultUser\n);\n```\n\nTo avoid this error, first assign the result of the ternary expression to a variable:\n\n```js\nvar accountToCheck =\n    (isLoggedIn(user) \u0026\u0026 user.admin) ? user : defaultUser;\n\ncheckAccount(accountToCheck);\n```\n\n#### Rule `\"where\"` Configuration: Return\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/where\": [ \"error\", { \"argument\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nfunction lookupAccount(userID = -1) {\n    return (\n        userID != -1 ? users[userID] : defaultUser\n    );\n}\n```\n\nTo avoid this error, first assign the result of the ternary expression to a variable:\n\n```js\nfunction lookupAccount(userID = -1) {\n    var user =\n        userID != -1 ? users[userID] : defaultUser;\n\n    return user;\n}\n```\n\n#### Rule `\"where\"` Configuration: Default\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/where\": [ \"error\", { \"default\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nfunction createUser(data,cb = data.adminUser ? onAdminUser : () =\u003e {}) {\n    // ..\n    cb(user);\n}\n```\n\nTo avoid this error, (re)assign the variable manually:\n\n```js\nfunction createUser(data,cb) {\n    cb =\n        cb !== undefined ? cb          :\n        data.adminUser   ? onAdminUser :\n        () =\u003e {};\n\n    // ..\n    cb(user);\n}\n```\n\n#### Rule `\"where\"` Configuration: Sub\n\nTo configure this rule mode off (on by default):\n\n```json\n\"@getify/proper-ternary/where\": [ \"error\", { \"sub\": false } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar isAllowed = !(\n    (userSession != null)\n        ? userSession.user.accountType == \"customer\"\n        : defaultAccountType == \"vendor\"\n);\n```\n\nTo avoid this error, first assign the result of the ternary expression to a variable:\n\n```js\nvar basicAccountType =\n    (userSession != null)\n        ? userSession.user.accountType == \"customer\"\n        : defaultAccountType == \"vendor\";\n\nvar isAllowed = !basicAccountType;\n```\n\n#### Rule `\"where\"` Configuration: Assignment\n\n**Note:** It's unlikely that you'll want to disable ternary expressions in assignment expressions (ie, `x = y ? z : w`), as this is basically where they're most naturally useful. This rule mode is included for completeness sake, but if you're inclined to turn it on, you perhaps might just consider disabling all ternary expressions with the built-in [\"no-ternary\" rule](https://eslint.org/docs/rules/no-ternary).\n\nTo configure this rule mode **on** (**off** by default):\n\n```json\n\"@getify/proper-ternary/where\": [ \"error\", { \"assignment\": true } ]\n```\n\nIf this mode is on (default), it will report an error for:\n\n```js\nvar name = userRecord != null ? userRecord.name : \"Kyle\";\n```\n\nTo avoid this error, use an `if..else` statement instead of a ternary expression:\n\n```js\nvar name;\nif (userRecord != null) {\n    name = userRecord.name;\n}\nelse {\n    name = \"Kyle\";\n}\n```\n\n## npm Package\n\nTo use this plugin with a global install of ESLint (recommended):\n\n```cmd\nnpm install -g @getify/eslint-plugin-proper-ternary\n```\n\nTo use this plugin with a local install of ESLint:\n\n```cmd\nnpm install @getify/eslint-plugin-proper-ternary\n```\n\n## Builds\n\n[![Build Status](https://travis-ci.org/getify/eslint-plugin-proper-ternary.svg?branch=master)](https://travis-ci.org/getify/eslint-plugin-proper-ternary)\n[![npm Module](https://badge.fury.io/js/%40getify%2Feslint-plugin-proper-ternary.svg)](https://www.npmjs.org/package/@getify/eslint-plugin-proper-ternary)\n\nIf you need to bundle/distribute this eslint plugin, use `dist/eslint-plugin-proper-ternary.js`, which comes pre-built with the npm package distribution; you shouldn't need to rebuild it under normal circumstances.\n\nHowever, if you download this repository via Git:\n\n1. The included build utility (`scripts/build-core.js`) builds (and minifies) `dist/eslint-plugin-proper-ternary.js` from source.\n\n2. To install the build and test dependencies, run `npm install` from the project root directory.\n\n3. To manually run the build utility with npm:\n\n    ```cmd\n    npm run build\n    ```\n\n4. To run the build utility directly without npm:\n\n    ```cmd\n    node scripts/build-core.js\n    ```\n\n## Tests\n\nA comprehensive test suite is included in this repository, as well as the npm package distribution. The default test behavior runs the test suite against `lib/index.js`.\n\n1. The included Node.js test utility (`scripts/node-tests.js`) runs the test suite.\n\n2. Ensure the test dependencies are installed by running `npm install` from the project root directory.\n\n    - **Note:** Starting with npm v5, the test utility is **not** run automatically during this `npm install`. With npm v4 and before, the test utility automatically runs at this point.\n\n3. To run the test utility with npm:\n\n    ```cmd\n    npm test\n    ```\n\n    Other npm test scripts:\n\n    * `npm run test:dist` will run the test suite against `dist/eslint-plugins-proper-ternary.js` instead of the default of `lib/index.js`.\n\n    * `npm run test:package` will run the test suite as if the package had just been installed via npm. This ensures `package.json`:`main` properly references `dist/eslint-plugins-proper-ternary.js` for inclusion.\n\n    * `npm run test:all` will run all three modes of the test suite.\n\n4. To run the test utility directly without npm:\n\n    ```cmd\n    node scripts/node-tests.js\n    ```\n\n### Test Coverage\n\n[![Coverage Status](https://coveralls.io/repos/github/getify/eslint-plugin-proper-ternary/badge.svg?branch=master)](https://coveralls.io/github/getify/eslint-plugin-proper-ternary?branch=master)\n\nIf you have [Istanbul](https://github.com/gotwarlost/istanbul) already installed on your system (requires v1.0+), you can use it to check the test coverage:\n\n```cmd\nnpm run coverage\n```\n\nThen open up `coverage/lcov-report/index.html` in a browser to view the report.\n\nTo run Istanbul directly without npm:\n\n```cmd\nistanbul cover scripts/node-tests.js\n```\n\n**Note:** The npm script `coverage:report` is only intended for use by project maintainers; it sends coverage reports to [Coveralls](https://coveralls.io/).\n\n## License\n\nAll code and documentation are (c) 2019-2021 Kyle Simpson and released under the [MIT License](http://getify.mit-license.org/). A copy of the MIT License [is also included](LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetify%2Feslint-plugin-proper-ternary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetify%2Feslint-plugin-proper-ternary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetify%2Feslint-plugin-proper-ternary/lists"}