packages/react-dom-bindings/src/client/ReactDOMInput.js JAVASCRIPT 485 lines View on github.com → Search inside
1/**2 * Copyright (c) Meta Platforms, Inc. and affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */910// TODO: direct imports like some-package/src/* are bad. Fix me.11import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCurrentFiber';1213import {getFiberCurrentPropsFromNode} from './ReactDOMComponentTree';14import {getToStringValue, toString} from './ToStringValue';15import {track, trackHydrated, updateValueIfChanged} from './inputValueTracking';16import {17  disableInputAttributeSyncing,18  enableHydrationChangeEvent,19} from 'shared/ReactFeatureFlags';20import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion';2122import type {ToStringValue} from './ToStringValue';23import escapeSelectorAttributeValueInsideDoubleQuotes from './escapeSelectorAttributeValueInsideDoubleQuotes';24import {queueChangeEvent} from '../events/ReactDOMEventReplaying';2526let didWarnValueDefaultValue = false;27let didWarnCheckedDefaultChecked = false;2829/**30 * Implements an <input> host component that allows setting these optional31 * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.32 *33 * If `checked` or `value` are not supplied (or null/undefined), user actions34 * that affect the checked state or value will trigger updates to the element.35 *36 * If they are supplied (and not null/undefined), the rendered element will not37 * trigger updates to the element. Instead, the props must change in order for38 * the rendered element to be updated.39 *40 * The rendered element will be initialized as unchecked (or `defaultChecked`)41 * with an empty value (or `defaultValue`).42 *43 * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html44 */4546export function validateInputProps(element: Element, props: Object) {47  if (__DEV__) {48    // Normally we check for undefined and null the same, but explicitly specifying both49    // properties, at all is probably worth warning for. We could move this either direction50    // and just make it ok to pass null or just check hasOwnProperty.51    if (52      props.checked !== undefined &&53      props.defaultChecked !== undefined &&54      !didWarnCheckedDefaultChecked55    ) {56      console.error(57        '%s contains an input of type %s with both checked and defaultChecked props. ' +58          'Input elements must be either controlled or uncontrolled ' +59          '(specify either the checked prop, or the defaultChecked prop, but not ' +60          'both). Decide between using a controlled or uncontrolled input ' +61          'element and remove one of these props. More info: ' +62          'https://react.dev/link/controlled-components',63        getCurrentFiberOwnerNameInDevOrNull() || 'A component',64        props.type,65      );66      didWarnCheckedDefaultChecked = true;67    }68    if (69      props.value !== undefined &&70      props.defaultValue !== undefined &&71      !didWarnValueDefaultValue72    ) {73      console.error(74        '%s contains an input of type %s with both value and defaultValue props. ' +75          'Input elements must be either controlled or uncontrolled ' +76          '(specify either the value prop, or the defaultValue prop, but not ' +77          'both). Decide between using a controlled or uncontrolled input ' +78          'element and remove one of these props. More info: ' +79          'https://react.dev/link/controlled-components',80        getCurrentFiberOwnerNameInDevOrNull() || 'A component',81        props.type,82      );83      didWarnValueDefaultValue = true;84    }85  }86}8788export function updateInput(89  element: Element,90  value: ?string,91  defaultValue: ?string,92  lastDefaultValue: ?string,93  checked: ?boolean,94  defaultChecked: ?boolean,95  type: ?string,96  name: ?string,97) {98  const node: HTMLInputElement = element as any;99100  // Temporarily disconnect the input from any radio buttons.101  // Changing the type or name as the same time as changing the checked value102  // needs to be atomically applied. We can only ensure that by disconnecting103  // the name while do the mutations and then reapply the name after that's done.104  node.name = '';105106  if (107    type != null &&108    typeof type !== 'function' &&109    typeof type !== 'symbol' &&110    typeof type !== 'boolean'111  ) {112    if (__DEV__) {113      checkAttributeStringCoercion(type, 'type');114    }115    node.type = type;116  } else {117    node.removeAttribute('type');118  }119120  if (value != null) {121    if (type === 'number') {122      if (123        // "" == 0, so a cleared field wouldn't otherwise be restored to 0.124        // $FlowFixMe[incompatible-type]125        // $FlowFixMe[invalid-compare]126        (value === 0 && node.value === '') ||127        // We explicitly want to coerce to number here if possible, so that128        // other spellings of the same number (e.g. "0.0" mid-edit) aren't129        // clobbered while the user types.130        // eslint-disable-next-line131        node.value != (value as any)132      ) {133        node.value = toString(getToStringValue(value));134      }135    } else if (node.value !== toString(getToStringValue(value))) {136      node.value = toString(getToStringValue(value));137    }138  } else if (type === 'submit' || type === 'reset') {139    // Submit/reset inputs need the attribute removed completely to avoid140    // blank-text buttons.141    node.removeAttribute('value');142  }143144  if (disableInputAttributeSyncing) {145    // When not syncing the value attribute, React only assigns a new value146    // whenever the defaultValue React prop has changed. When not present,147    // React does nothing148    if (defaultValue != null) {149      setDefaultValue(node, getToStringValue(defaultValue));150    } else if (lastDefaultValue != null) {151      node.removeAttribute('value');152    }153  } else {154    // When syncing the value attribute, the value comes from a cascade of155    // properties:156    //  1. The value React property157    //  2. The defaultValue React property158    //  3. Otherwise there should be no change159    if (value != null) {160      if (161        type === 'number' &&162        // We explicitly want to coerce to number here if possible.163        // eslint-disable-next-line164        node.value == (value as any)165      ) {166        // node.value may be a different spelling of the same number (e.g.167        // "0.0" for 0). Mirror what's displayed, like the value setter does.168        // Not redundant with the assignment above: browsers sanitize invalid169        // assigned values to "", in which case we sync the React value below.170        setDefaultValue(node, getToStringValue(node.value));171      } else {172        setDefaultValue(node, getToStringValue(value));173      }174    } else if (defaultValue != null) {175      setDefaultValue(node, getToStringValue(defaultValue));176    } else if (lastDefaultValue != null) {177      node.removeAttribute('value');178    }179  }180181  if (disableInputAttributeSyncing) {182    // When not syncing the checked attribute, the attribute is directly183    // controllable from the defaultValue React property. It needs to be184    // updated as new props come in.185    if (defaultChecked == null) {186      node.removeAttribute('checked');187    } else {188      node.defaultChecked = !!defaultChecked;189    }190  } else {191    // When syncing the checked attribute, it only changes when it needs192    // to be removed, such as transitioning from a checkbox into a text input193    if (checked == null && defaultChecked != null) {194      node.defaultChecked = !!defaultChecked;195    }196  }197198  if (checked != null) {199    // Important to set this even if it's not a change in order to update input200    // value tracking with radio buttons201    // TODO: Should really update input value tracking for the whole radio202    // button group in an effect or something (similar to #27024)203    node.checked =204      checked && typeof checked !== 'function' && typeof checked !== 'symbol';205  }206207  if (208    name != null &&209    typeof name !== 'function' &&210    typeof name !== 'symbol' &&211    typeof name !== 'boolean'212  ) {213    if (__DEV__) {214      checkAttributeStringCoercion(name, 'name');215    }216    node.name = toString(getToStringValue(name));217  } else {218    node.removeAttribute('name');219  }220}221222export function initInput(223  element: Element,224  value: ?string,225  defaultValue: ?string,226  checked: ?boolean,227  defaultChecked: ?boolean,228  type: ?string,229  name: ?string,230  isHydrating: boolean,231) {232  const node: HTMLInputElement = element as any;233234  if (235    type != null &&236    typeof type !== 'function' &&237    typeof type !== 'symbol' &&238    typeof type !== 'boolean'239  ) {240    if (__DEV__) {241      checkAttributeStringCoercion(type, 'type');242    }243    node.type = type;244  }245246  if (value != null || defaultValue != null) {247    const isButton = type === 'submit' || type === 'reset';248249    // Avoid setting value attribute on submit/reset inputs as it overrides the250    // default value provided by the browser. See: #12872251    if (isButton && (value === undefined || value === null)) {252      // We track the value just in case it changes type later on.253      track(element as any);254      return;255    }256257    const defaultValueStr =258      defaultValue != null ? toString(getToStringValue(defaultValue)) : '';259    const initialValue =260      value != null ? toString(getToStringValue(value)) : defaultValueStr;261262    // Do not assign value if it is already set. This prevents user text input263    // from being lost during SSR hydration.264    if (!isHydrating || enableHydrationChangeEvent) {265      if (disableInputAttributeSyncing) {266        // When not syncing the value attribute, the value property points267        // directly to the React prop. Only assign it if it exists.268        if (value != null) {269          // Always assign on buttons so that it is possible to assign an270          // empty string to clear button text.271          //272          // Otherwise, do not re-assign the value property if is empty. This273          // potentially avoids a DOM write and prevents Firefox (~60.0.1) from274          // prematurely marking required inputs as invalid. Equality is compared275          // to the current value in case the browser provided value is not an276          // empty string.277          if (isButton || toString(getToStringValue(value)) !== node.value) {278            node.value = toString(getToStringValue(value));279          }280        }281      } else {282        // When syncing the value attribute, the value property should use283        // the wrapperState._initialValue property. This uses:284        //285        //   1. The value React property when present286        //   2. The defaultValue React property when present287        //   3. An empty string288        if (initialValue !== node.value) {289          node.value = initialValue;290        }291      }292    }293294    if (disableInputAttributeSyncing) {295      // When not syncing the value attribute, assign the value attribute296      // directly from the defaultValue React property (when present)297      if (defaultValue != null) {298        node.defaultValue = defaultValueStr;299      }300    } else {301      // Otherwise, the value attribute is synchronized to the property,302      // so we assign defaultValue to the same thing as the value property303      // assignment step above.304      node.defaultValue = initialValue;305    }306  }307308  // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug309  // this is needed to work around a chrome bug where setting defaultChecked310  // will sometimes influence the value of checked (even after detachment).311  // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416312  // We need to temporarily unset name to avoid disrupting radio button groups.313314  const checkedOrDefault = checked != null ? checked : defaultChecked;315  // TODO: This 'function' or 'symbol' check isn't replicated in other places316  // so this semantic is inconsistent.317  const initialChecked =318    typeof checkedOrDefault !== 'function' &&319    typeof checkedOrDefault !== 'symbol' &&320    !!checkedOrDefault;321322  if (isHydrating && !enableHydrationChangeEvent) {323    // Detach .checked from .defaultChecked but leave user input alone324    node.checked = node.checked;325  } else {326    node.checked = !!initialChecked;327  }328329  if (disableInputAttributeSyncing) {330    // Only assign the checked attribute if it is defined. This saves331    // a DOM write when controlling the checked attribute isn't needed332    // (text inputs, submit/reset)333    if (defaultChecked != null) {334      node.defaultChecked = !node.defaultChecked;335      node.defaultChecked = !!defaultChecked;336    }337  } else {338    // When syncing the checked attribute, both the checked property and339    // attribute are assigned at the same time using defaultChecked. This uses:340    //341    //   1. The checked React property when present342    //   2. The defaultChecked React property when present343    //   3. Otherwise, false344    node.defaultChecked = !node.defaultChecked;345    node.defaultChecked = !!initialChecked;346  }347348  // Name needs to be set at the end so that it applies atomically to connected radio buttons.349  if (350    name != null &&351    typeof name !== 'function' &&352    typeof name !== 'symbol' &&353    typeof name !== 'boolean'354  ) {355    if (__DEV__) {356      checkAttributeStringCoercion(name, 'name');357    }358    node.name = name;359  }360  track(element as any);361}362363export function hydrateInput(364  element: Element,365  value: ?string,366  defaultValue: ?string,367  checked: ?boolean,368  defaultChecked: ?boolean,369): void {370  const node: HTMLInputElement = element as any;371372  const defaultValueStr =373    defaultValue != null ? toString(getToStringValue(defaultValue)) : '';374  const initialValue =375    value != null ? toString(getToStringValue(value)) : defaultValueStr;376377  const checkedOrDefault = checked != null ? checked : defaultChecked;378  // TODO: This 'function' or 'symbol' check isn't replicated in other places379  // so this semantic is inconsistent.380  const initialChecked =381    typeof checkedOrDefault !== 'function' &&382    typeof checkedOrDefault !== 'symbol' &&383    !!checkedOrDefault;384385  // Detach .checked from .defaultChecked but leave user input alone386  node.checked = node.checked;387388  const changed = trackHydrated(node as any, initialValue, initialChecked);389  if (changed) {390    // If the current value is different, that suggests that the user391    // changed it before hydration. Queue a replay of the change event.392    // For radio buttons the change event only fires on the selected one.393    if (node.type !== 'radio' || node.checked) {394      queueChangeEvent(node);395    }396  }397}398399export function restoreControlledInputState(element: Element, props: Object) {400  const rootNode: HTMLInputElement = element as any;401  updateInput(402    rootNode,403    props.value,404    props.defaultValue,405    props.defaultValue,406    props.checked,407    props.defaultChecked,408    props.type,409    props.name,410  );411  const name = props.name;412  if (props.type === 'radio' && name != null) {413    let queryRoot: Element = rootNode;414415    while (queryRoot.parentNode) {416      queryRoot = queryRoot.parentNode as any as Element;417    }418419    // If `rootNode.form` was non-null, then we could try `form.elements`,420    // but that sometimes behaves strangely in IE8. We could also try using421    // `form.getElementsByName`, but that will only return direct children422    // and won't include inputs that use the HTML5 `form=` attribute. Since423    // the input might not even be in a form. It might not even be in the424    // document. Let's just use the local `querySelectorAll` to ensure we don't425    // miss anything.426    if (__DEV__) {427      checkAttributeStringCoercion(name, 'name');428    }429    const group = queryRoot.querySelectorAll(430      'input[name="' +431        escapeSelectorAttributeValueInsideDoubleQuotes('' + name) +432        '"][type="radio"]',433    );434435    for (let i = 0; i < group.length; i++) {436      const otherNode = group[i] as any as HTMLInputElement;437      if (otherNode === rootNode || otherNode.form !== rootNode.form) {438        continue;439      }440      // This will throw if radio buttons rendered by different copies of React441      // and the same name are rendered into the same form (same as #1939).442      // That's probably okay; we don't support it just as we don't support443      // mixing React radio buttons with non-React ones.444      const otherProps: any = getFiberCurrentPropsFromNode(otherNode);445446      if (!otherProps) {447        throw new Error(448          'ReactDOMInput: Mixing React and non-React radio inputs with the ' +449            'same `name` is not supported.',450        );451      }452453      // If this is a controlled radio button group, forcing the input that454      // was previously checked to update will cause it to be come re-checked455      // as appropriate.456      updateInput(457        otherNode,458        otherProps.value,459        otherProps.defaultValue,460        otherProps.defaultValue,461        otherProps.checked,462        otherProps.defaultChecked,463        otherProps.type,464        otherProps.name,465      );466    }467468    // If any updateInput() call set .checked to true, an input in this group469    // (often, `rootNode` itself) may have become unchecked470    for (let i = 0; i < group.length; i++) {471      const otherNode = group[i] as any as HTMLInputElement;472      if (otherNode.form !== rootNode.form) {473        continue;474      }475      updateValueIfChanged(otherNode);476    }477  }478}479480function setDefaultValue(node: HTMLInputElement, value: ToStringValue) {481  if (node.defaultValue !== toString(value)) {482    node.defaultValue = toString(value);483  }484}

Code quality findings 80

Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
props.checked !== undefined &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
props.defaultChecked !== undefined &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
props.value !== undefined &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
props.defaultValue !== undefined &&
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
type != null &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof type !== 'function' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof type !== 'function' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof type !== 'symbol' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof type !== 'symbol' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof type !== 'boolean'
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof type !== 'boolean'
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (type === 'number') {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
// "" == 0, so a cleared field wouldn't otherwise be restored to 0.
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
(value === 0 && node.value === '') ||
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
node.value != (value as any)
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (node.value !== toString(getToStringValue(value))) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (type === 'submit' || type === 'reset') {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (defaultValue != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
} else if (lastDefaultValue != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
type === 'number' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
node.value == (value as any)
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
} else if (defaultValue != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
} else if (lastDefaultValue != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (defaultChecked == null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (checked == null && defaultChecked != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (checked == null && defaultChecked != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (checked != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
checked && typeof checked !== 'function' && typeof checked !== 'symbol';
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
checked && typeof checked !== 'function' && typeof checked !== 'symbol';
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
name != null &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof name !== 'function' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof name !== 'function' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof name !== 'symbol' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof name !== 'symbol' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof name !== 'boolean'
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof name !== 'boolean'
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
type != null &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof type !== 'function' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof type !== 'function' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof type !== 'symbol' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof type !== 'symbol' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof type !== 'boolean'
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof type !== 'boolean'
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value != null || defaultValue != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const isButton = type === 'submit' || type === 'reset';
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (isButton && (value === undefined || value === null)) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
defaultValue != null ? toString(getToStringValue(defaultValue)) : '';
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
value != null ? toString(getToStringValue(value)) : defaultValueStr;
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (value != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (isButton || toString(getToStringValue(value)) !== node.value) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (initialValue !== node.value) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (defaultValue != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
const checkedOrDefault = checked != null ? checked : defaultChecked;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof checkedOrDefault !== 'function' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof checkedOrDefault !== 'function' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof checkedOrDefault !== 'symbol' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof checkedOrDefault !== 'symbol' &&
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (defaultChecked != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
name != null &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof name !== 'function' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof name !== 'function' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof name !== 'symbol' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof name !== 'symbol' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof name !== 'boolean'
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof name !== 'boolean'
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
defaultValue != null ? toString(getToStringValue(defaultValue)) : '';
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
value != null ? toString(getToStringValue(value)) : defaultValueStr;
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
const checkedOrDefault = checked != null ? checked : defaultChecked;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof checkedOrDefault !== 'function' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof checkedOrDefault !== 'function' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
typeof checkedOrDefault !== 'symbol' &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
typeof checkedOrDefault !== 'symbol' &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (node.type !== 'radio' || node.checked) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (props.type === 'radio' && name != null) {
Use strict inequality (!==) to prevent type coercion bugs
info correctness loose-inequality
if (props.type === 'radio' && name != null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (otherNode === rootNode || otherNode.form !== rootNode.form) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (otherNode.form !== rootNode.form) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (node.defaultValue !== toString(value)) {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.