Eslint: no-unneeded-ternary false positive

Created on 2 Mar 2017  路  3Comments  路  Source: eslint/eslint

Tell us about your environment

  • ESLint Version: 3.16.1
  • Node Version: 7.7.1
  • npm Version: 4.1.2

What parser (default, Babel-ESLint, etc.) are you using?

Default

Please show your full configuration:

rules:
  # See: http://eslint.org/docs/rules/

  # Possible Errors

  no-await-in-loop: 0
  no-cond-assign: [2, always]
  no-console: 2
  no-constant-condition: 2
  no-control-regex: 2
  no-debugger: 2
  no-dupe-args: 2
  no-dupe-keys: 2
  no-duplicate-case: 2
  no-empty-character-class: 2
  no-empty: 2
  no-ex-assign: 2
  no-extra-boolean-cast: 2
  no-extra-parens: 0
  no-extra-semi: 2
  no-func-assign: 2
  no-inner-declarations: 2
  no-invalid-regexp: 2
  no-irregular-whitespace: 2
  no-obj-calls: 2
  no-prototype-builtins: 0
  no-regex-spaces: 2
  no-sparse-arrays: 2
  no-unexpected-multiline: 2
  no-unreachable: 2
  no-unsafe-finally: 2
  no-unsafe-negation: 2
  use-isnan: 2
  valid-jsdoc: 2
  valid-typeof: 2

  # Best Practices

  accessor-pairs: 0
  array-callback-return: 2
  block-scoped-var: 2
  complexity: [1, 18]
  consistent-return: 0
  curly: [2, all]
  default-case: 0
  dot-location: [2, object]
  dot-notation: 2
  eqeqeq: 2
  guard-for-in: 2
  no-alert: 2
  no-caller: 2
  no-case-declarations: 2
  no-div-regex: 2
  no-else-return: 2
  no-empty-function: 0
  no-empty-pattern: 2
  no-eq-null: 2
  no-eval: 2
  no-extend-native: 2
  no-extra-bind: 2
  no-extra-label: 2
  no-fallthrough: 0
  no-floating-decimal: 2
  no-global-assign: 2
  no-implicit-coercion: 2
  no-implicit-globals: 2
  no-implied-eval: 2
  no-invalid-this: 2
  no-iterator: 2
  no-labels: [2, { allowLoop: true }]
  no-lone-blocks: 2
  no-loop-func: 2
  no-magic-numbers: 0
  no-multi-spaces: 2
  no-multi-str: 2
  no-new-func: 2
  no-new-wrappers: 2
  no-new: 2
  no-octal-escape: 2
  no-octal: 2
  no-param-reassign: 0
  no-proto: 2
  no-redeclare: 2
  no-restricted-properties: 0
  no-return-assign: 0
  no-return-await: 2
  no-script-url: 2
  no-self-assign: 2
  no-self-compare: 2
  no-sequences: 2
  no-throw-literal: 2
  no-unmodified-loop-condition: 2
  no-unused-expressions: 2
  no-unused-labels: 2
  no-useless-call: 2
  no-useless-concat: 2
  no-useless-escape: 2
  no-useless-return: 2
  no-void: 2
  no-warning-comments: 1
  no-with: 2
  prefer-promise-reject-errors: 2
  radix: 2
  require-await: 2
  vars-on-top: 0
  wrap-iife: [2, outside]
  yoda: 2

  # Strict Mode

  strict: [2, global]

  # Variables

  init-declarations: 0
  no-catch-shadow: 0
  no-delete-var: 2
  no-label-var: 2
  no-restricted-globals: 0
  no-shadow-restricted-names: 2
  no-shadow: 0
  no-undef-init: 2
  no-undef: 2
  no-undefined: 0
  no-unused-vars: 2
  no-use-before-define: 2

  # Node.js and CommonJS

  callback-return: 2
  global-require: 0
  handle-callback-err: [2, "^(err|error)$"]
  no-mixed-requires: 2
  no-new-require: 2
  no-path-concat: 2
  no-process-env: 0
  no-process-exit: 2
  no-restricted-modules: 0
  no-sync: 0

  # Stylistic Issues (we don't check style with ESLint)

  array-bracket-spacing: [2, "never"]
  block-spacing: [2, "always"]
  brace-style: [2, "1tbs"]
  camelcase: 2
  capitalized-comments: 0
  comma-dangle: [2, "never"]
  comma-spacing: [2, { before: false, after: true }]
  comma-style: [2, "last"]
  computed-property-spacing: [2, "never"]
  consistent-this: [2, "that"]
  eol-last: [2, "always"]
  func-call-spacing: [2, "never"]
  func-name-matching: 0
  func-names: 0
  func-style: [2, "declaration", { allowArrowFunctions: true }]
  id-blacklist: 0
  id-length: 0
  id-match: 0
  indent: [2, "tab"]
  jsx-quotes: [2, "prefer-double"]
  key-spacing: [2, { beforeColon: false, afterColon: true, mode: strict }]
  keyword-spacing: [2, { before: true, after: true }]
  line-comment-position: 0
  linebreak-style: [2, "unix"]
  lines-around-comment: [2, { beforeBlockComment: true }]
  lines-around-directive: 0
  max-depth: [1, 6]
  max-len: [2, { code: 120, tabWidth: 4, ignoreUrls: true }]
  max-lines: [1, { max: 1000, skipBlankLines: true, skipComments: true }]
  max-nested-callbacks: [1, 6]
  max-params: 0
  max-statements-per-line: [2, { max: 1 }]
  max-statements: 0
  multiline-ternary: 0
  new-cap: 2
  new-parens: 2
  newline-after-var: 0
  newline-before-return: 0
  newline-per-chained-call: 0
  no-array-constructor: 0
  no-bitwise: 0
  no-continue: 0
  no-inline-comments: 0
  no-lonely-if: 2
  no-mixed-operators: 2
  no-mixed-spaces-and-tabs: [2, "smart-tabs"]
  no-multi-assign: 0
  no-multiple-empty-lines: [2, { max: 2, maxEOF: 1, maxBOF: 0 }]
  no-negated-condition: 2
  no-nested-ternary: 2
  no-new-object: 2
  no-plusplus: 2
  no-restricted-syntax: [2, "WithStatement"]
  no-tabs: 0
  no-ternary: 0
  no-trailing-spaces: 2
  no-underscore-dangle: 0
  no-unneeded-ternary: 2
  no-whitespace-before-property: 2
  object-curly-newline: 0
  object-curly-spacing: [2, "always"]
  object-property-newline: 0
  one-var-declaration-per-line: 0
  one-var: 0
  operator-assignment: [2, "always"]
  operator-linebreak: [2, "after"]
  padded-blocks: [2, "never"]
  quote-props: [2, "as-needed"]
  quotes: [2, "single", { avoidEscape: true, allowTemplateLiterals: true }]
  require-jsdoc: 0
  semi-spacing: [2, { before: false, after: true }]
  semi: [2, "always"]
  sort-keys: 0
  sort-vars: 0
  space-before-blocks: [2, "always"]
  space-before-function-paren: [2, { anonymous: "always", named: "never", asyncArrow: "always" }]
  space-in-parens: [2, "never"]
  space-infix-ops: 2
  space-unary-ops: [2, { words: true, nonwords: false }]
  spaced-comment: [2, "always"]
  unicode-bom: [2, "never"]
  wrap-regex: 0

  # ECMAScript 6

  arrow-body-style: [2, "always"]
  arrow-parens: [2, "always"]
  arrow-spacing: 2
  constructor-super: 2
  generator-star-spacing: 2
  no-class-assign: 2
  no-confusing-arrow: 2
  no-const-assign: 2
  no-dupe-class-members: 2
  no-duplicate-imports: 2
  no-new-symbol: 2
  no-restricted-imports: 0
  no-this-before-super: 2
  no-useless-computed-key: 2
  no-useless-constructor: 2
  no-useless-rename: 2
  no-var: 2
  object-shorthand: 2
  prefer-arrow-callback: 2
  prefer-const: 2
  prefer-destructuring: 0
  prefer-numeric-literals: 2
  prefer-rest-params: 2
  prefer-spread: 2
  prefer-template: 2
  require-yield: 2
  rest-spread-spacing: [2, never]
  sort-imports: 0
  symbol-description: 0
  template-curly-spacing: [2, never]
  yield-star-spacing: [2, after]

env:
  es6: true
  node: true

What did you do? Please include the actual source code causing the issue.

function MyClass(options) {
  this.isCancellable = options && options.cancellable ? true : false;
}

What did you expect to happen?

No error. I want this.isCancellable to always be boolean. If options is undefined, the code above translates to this.isCancellable = undefined ? true : false;. I don't consider this an unnecessary ternary, because not having it won't assign false to my property, but undefined instead.

This is not the same as the absolutely valid cases that the documentation describes, where all conditions immediately return booleans, eg.: var a = x === 2 ? true : false;

What actually happened? Please include the actual, raw output from ESLint.

  42:56  error  Unnecessary use of boolean literals in conditional expression  no-unneeded-ternary
archived due to age question

All 3 comments

The ternary is unnecessary because you could use either of the following constructs instead:

this.isCancellable = !!(options && options.cancellable);

this.isCancellable = Boolean (options && options.cancellable);

Yes, I could cast. I don't know if that ability should be related to this rule though. I'll leave that up to you guys to decide :) No biggy either way.

The rule seems to be behaving as intended, so i'll close this.
@ronkorving thanks for the report, anyway! If you feel strongly that this rule shouldn't report cases that need casting, you can always open a separate issue with a rule-enhancement proposal.

Was this page helpful?
0 / 5 - 0 ratings