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
| Aspect | Details |
|---|---|
| Severity | Warning (organization) |
| Auto-Fix | ❌ No (requires reordering) |
| Category | React |
| ESLint MCP | ✅ Optimized for ESLint MCP integration |
| Best For | React 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
| Issue | Impact | Solution |
|---|---|---|
| 🔄 Scattered statics | Properties hard to find | Group together |
| 🐛 Inconsistent placement | Different patterns across codebase | Standardize location |
| 🔍 Review difficulty | Time wasted searching | Predictable structure |
Default Property Groups
| Group Name | Properties |
|---|---|
propTypes | propTypes, defaultProps, childContextTypes, contextTypes, contextType |
lifecycle | getDerivedStateFromProps, 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
| Option | Type | Default | Description |
|---|---|---|---|
propertyGroups | array | See defaults | Define property groups |
childClass | string | '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'
}
}Related Rules
sort-comp- Method orderingprop-types- Enforce PropTypes
Further Reading
- Static Properties - React docs
- Class Fields - MDN
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 analyzedMitigation: 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 trackedMitigation: Ensure imported values follow the same constraints. Use TypeScript for type safety.