Skip to main content
ESLint Interlace
Plugin: react-featuresRules

static-property-placement

static-property-placement rule

Keywords: React, static properties, propTypes, defaultProps, organization, ESLint rule, LLM-optimized

Enforce static property placement in React class components. This rule is part of eslint-plugin-react-features.

Quick Summary

AspectDetails
SeverityWarning (organization)
Auto-Fix❌ No (requires reordering)
CategoryReact
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForReact class components with consistent structure

Rule Details

Enforces consistent placement and grouping of static properties like propTypes, defaultProps, contextTypes, and lifecycle static methods.

Why This Matters

IssueImpactSolution
🔄 Scattered staticsProperties hard to findGroup together
🐛 Inconsistent placementDifferent patterns across codebaseStandardize location
🔍 Review difficultyTime wasted searchingPredictable structure

Default Property Groups

Group NameProperties
propTypespropTypes, defaultProps, childContextTypes, contextTypes, contextType
lifecyclegetDerivedStateFromProps, getDerivedStateFromError

Examples

❌ Incorrect

Awaiting a tested example. The previous snippet was removed because the rule does not behave as the doc claimed; track the regression in benchmarks/FP_FN_REMEDIATION_TRACKER.md.

✅ Correct

class UserCard extends React.Component {
  // GOOD: All prop-related statics grouped together
  static propTypes = {
    name: PropTypes.string.isRequired,
    email: PropTypes.string,
  };
  
  static defaultProps = {
    name: 'Guest',
    email: '',
  };
  
  static contextTypes = {
    theme: PropTypes.object
  };
  
  // GOOD: Lifecycle statics grouped together
  static getDerivedStateFromProps(props, state) {
    if (props.name !== state.prevName) {
      return { name: props.name, prevName: props.name };
    }
    return null;
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  // Instance properties after statics
  state = { loading: true, name: '' };
  
  componentDidMount() {
    this.fetchData();
  }
  
  render() {
    return <div>{this.state.name}</div>;
  }
}

// BETTER: Use functional components
function UserCard({ name = 'Guest', email = '' }) {
  const theme = useContext(ThemeContext);
  return <div style={theme}>{name}</div>;
}

UserCard.propTypes = {
  name: PropTypes.string,
  email: PropTypes.string,
};

Options

OptionTypeDefaultDescription
propertyGroupsarraySee defaultsDefine property groups
childClassstring'first'Where to place in subclasses

Configuration with Options

{
  rules: {
    'react-features/static-property-placement': ['warn', {
      propertyGroups: [
        {
          name: 'propTypes',
          properties: ['propTypes', 'defaultProps', 'contextTypes']
        },
        {
          name: 'lifecycle',
          properties: ['getDerivedStateFromProps', 'getDerivedStateFromError']
        },
        {
          name: 'custom',
          properties: ['displayName', 'navigationOptions']
        }
      ],
      childClass: 'first'
    }]
  }
}

Configuration Examples

Basic Usage

{
  rules: {
    'react-features/static-property-placement': 'warn'
  }
}

Further Reading

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Dynamic Variable References

Why: Static analysis cannot trace values stored in variables or passed through function parameters.

// ❌ NOT DETECTED - Prop from variable
const propValue = computedValue;
<Component prop={propValue} /> // Computation not analyzed

Mitigation: Implement runtime validation and review code manually. Consider using TypeScript branded types for validated inputs.

Imported Values

Why: When values come from imports, the rule cannot analyze their origin or construction.

// ❌ NOT DETECTED - Value from import
import { getValue } from './helpers';
processValue(getValue()); // Cross-file not tracked

Mitigation: Ensure imported values follow the same constraints. Use TypeScript for type safety.