eslint-plugin-nextfriday 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +24 -15
- package/docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md +211 -0
- package/docs/rules/PREFER_REACT_IMPORT_TYPES.md +175 -0
- package/docs/rules/REACT_PROPS_DESTRUCTURE.md +158 -0
- package/lib/index.cjs +317 -6
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +42 -0
- package/lib/index.d.ts +42 -0
- package/lib/index.js +317 -6
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# eslint-plugin-nextfriday
|
|
2
2
|
|
|
3
|
+
## 1.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#14](https://github.com/next-friday/eslint-plugin-nextfriday/pull/14) [`de54aaa`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/de54aaa42833ada9d847fe3885ab98b82e0590e9) Thanks [@nextfridaydeveloper](https://github.com/nextfridaydeveloper)! - Improved type checking logic across ESLint rules to enhance accuracy and reliability. This refactor focuses on better type inference, more precise type guards, and improved handling of edge cases in rule implementations.
|
|
8
|
+
|
|
9
|
+
## 1.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#12](https://github.com/next-friday/eslint-plugin-nextfriday/pull/12) [`30dc89f`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/30dc89f3c4d11c9cb320b8c3dfa370b7caff9ddc) Thanks [@nextfridaydeveloper](https://github.com/nextfridaydeveloper)! - Added two new ESLint rules to improve React development practices and code quality. The `prefer-react-import-types` rule enforces direct import of React types, while `prefer-interface-over-inline-types` promotes better type organization. Also improved the React component detection logic in the existing `react-props-destructure` rule.
|
|
14
|
+
|
|
3
15
|
## 1.0.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -59,23 +59,24 @@ export default [
|
|
|
59
59
|
nextfriday,
|
|
60
60
|
},
|
|
61
61
|
rules: {
|
|
62
|
-
// Base rules (suitable for all projects)
|
|
63
62
|
"nextfriday/no-emoji": "error",
|
|
64
63
|
"nextfriday/file-kebab-case": "error",
|
|
65
64
|
"nextfriday/md-filename-case-restriction": "error",
|
|
66
65
|
"nextfriday/prefer-destructuring-params": "error",
|
|
67
66
|
"nextfriday/no-explicit-return-type": "error",
|
|
68
67
|
"nextfriday/prefer-import-type": "error",
|
|
69
|
-
|
|
68
|
+
"nextfriday/prefer-react-import-types": "error",
|
|
70
69
|
"nextfriday/jsx-pascal-case": "error",
|
|
70
|
+
"nextfriday/prefer-interface-over-inline-types": "error",
|
|
71
|
+
"nextfriday/react-props-destructure": "error",
|
|
71
72
|
},
|
|
72
73
|
},
|
|
73
74
|
];
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
### Legacy Config
|
|
77
|
+
### Legacy Config (ESLint 8 and below)
|
|
77
78
|
|
|
78
|
-
#### Base Configuration
|
|
79
|
+
#### Base Legacy Configuration
|
|
79
80
|
|
|
80
81
|
```js
|
|
81
82
|
module.exports = {
|
|
@@ -84,7 +85,7 @@ module.exports = {
|
|
|
84
85
|
};
|
|
85
86
|
```
|
|
86
87
|
|
|
87
|
-
#### React Configuration
|
|
88
|
+
#### React Legacy Configuration
|
|
88
89
|
|
|
89
90
|
```js
|
|
90
91
|
module.exports = {
|
|
@@ -93,7 +94,7 @@ module.exports = {
|
|
|
93
94
|
};
|
|
94
95
|
```
|
|
95
96
|
|
|
96
|
-
#### Next.js Configuration
|
|
97
|
+
#### Next.js Legacy Configuration
|
|
97
98
|
|
|
98
99
|
```js
|
|
99
100
|
module.exports = {
|
|
@@ -104,15 +105,18 @@ module.exports = {
|
|
|
104
105
|
|
|
105
106
|
## Rules
|
|
106
107
|
|
|
107
|
-
| Rule
|
|
108
|
-
|
|
|
109
|
-
| [no-emoji](docs/rules/NO_EMOJI.md)
|
|
110
|
-
| [file-kebab-case](docs/rules/FILE_KEBAB_CASE.md)
|
|
111
|
-
| [jsx-pascal-case](docs/rules/JSX_PASCAL_CASE.md)
|
|
112
|
-
| [md-filename-case-restriction](docs/rules/MD_FILENAME_CASE_RESTRICTION.md)
|
|
113
|
-
| [prefer-destructuring-params](docs/rules/PREFER_DESTRUCTURING_PARAMS.md)
|
|
114
|
-
| [no-explicit-return-type](docs/rules/NO_EXPLICIT_RETURN_TYPE.md)
|
|
115
|
-
| [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md)
|
|
108
|
+
| Rule | Description | Fixable |
|
|
109
|
+
| -------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- |
|
|
110
|
+
| [no-emoji](docs/rules/NO_EMOJI.md) | Disallow emojis in code | ❌ |
|
|
111
|
+
| [file-kebab-case](docs/rules/FILE_KEBAB_CASE.md) | Enforce kebab-case filenames for .ts and .js files | ❌ |
|
|
112
|
+
| [jsx-pascal-case](docs/rules/JSX_PASCAL_CASE.md) | Enforce PascalCase filenames for .jsx and .tsx files | ❌ |
|
|
113
|
+
| [md-filename-case-restriction](docs/rules/MD_FILENAME_CASE_RESTRICTION.md) | Enforce SNAKE_CASE filenames for .md files | ❌ |
|
|
114
|
+
| [prefer-destructuring-params](docs/rules/PREFER_DESTRUCTURING_PARAMS.md) | Enforce destructuring for functions with multiple parameters | ❌ |
|
|
115
|
+
| [no-explicit-return-type](docs/rules/NO_EXPLICIT_RETURN_TYPE.md) | Disallow explicit return types on functions | ✅ |
|
|
116
|
+
| [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md) | Enforce using 'import type' for type-only imports | ✅ |
|
|
117
|
+
| [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
|
|
118
|
+
| [prefer-react-import-types](docs/rules/PREFER_REACT_IMPORT_TYPES.md) | Enforce direct imports from 'react' instead of React.X | ✅ |
|
|
119
|
+
| [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | ❌ |
|
|
116
120
|
|
|
117
121
|
## Configurations
|
|
118
122
|
|
|
@@ -128,6 +132,7 @@ Basic configuration without JSX-specific rules:
|
|
|
128
132
|
- `nextfriday/prefer-destructuring-params`: `"error"`
|
|
129
133
|
- `nextfriday/no-explicit-return-type`: `"error"`
|
|
130
134
|
- `nextfriday/prefer-import-type`: `"error"`
|
|
135
|
+
- `nextfriday/prefer-react-import-types`: `"error"`
|
|
131
136
|
|
|
132
137
|
#### `base/recommended`
|
|
133
138
|
|
|
@@ -141,6 +146,8 @@ Includes all base rules plus React-specific rules:
|
|
|
141
146
|
|
|
142
147
|
- All base rules above
|
|
143
148
|
- `nextfriday/jsx-pascal-case`: `"error"`
|
|
149
|
+
- `nextfriday/prefer-interface-over-inline-types`: `"error"`
|
|
150
|
+
- `nextfriday/react-props-destructure`: `"error"`
|
|
144
151
|
|
|
145
152
|
#### `react/recommended`
|
|
146
153
|
|
|
@@ -154,6 +161,8 @@ Includes all rules suitable for Next.js projects:
|
|
|
154
161
|
|
|
155
162
|
- All base rules
|
|
156
163
|
- `nextfriday/jsx-pascal-case`: `"error"`
|
|
164
|
+
- `nextfriday/prefer-interface-over-inline-types`: `"error"`
|
|
165
|
+
- `nextfriday/react-props-destructure`: `"error"`
|
|
157
166
|
|
|
158
167
|
#### `nextjs/recommended`
|
|
159
168
|
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# prefer-interface-over-inline-types
|
|
2
|
+
|
|
3
|
+
Enforce interface declarations over inline type annotations for React component props.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule enforces the use of interface declarations instead of inline type annotations for React component props when the type is complex. This promotes better code organization, reusability, and readability.
|
|
8
|
+
|
|
9
|
+
Examples of **incorrect** code for this rule:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
// More than 2 properties - should use interface
|
|
13
|
+
const Component = (props: { children: ReactNode; title: string; onClick: () => void }) => (
|
|
14
|
+
<div onClick={props.onClick}>
|
|
15
|
+
<h1>{props.title}</h1>
|
|
16
|
+
{props.children}
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
// Nested object types - should use interface
|
|
21
|
+
const Component = (props: { user: { name: string; age: number }; isActive: boolean }) => <div>{props.user.name}</div>;
|
|
22
|
+
|
|
23
|
+
// Array types - should use interface
|
|
24
|
+
const Component = (props: { items: string[]; title: string }) => (
|
|
25
|
+
<div>
|
|
26
|
+
<h1>{props.title}</h1>
|
|
27
|
+
{props.items.map((item) => (
|
|
28
|
+
<span key={item}>{item}</span>
|
|
29
|
+
))}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Union types - should use interface
|
|
34
|
+
const Component = (props: { status: "loading" | "success" | "error"; message: string }) => (
|
|
35
|
+
<div className={props.status}>{props.message}</div>
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Function declarations
|
|
39
|
+
function Component(props: { data: { id: number; name: string }; isVisible: boolean }) {
|
|
40
|
+
return <div>{props.data.name}</div>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Function expressions
|
|
44
|
+
const Component = function (props: { config: { theme: string; lang: string }; children: ReactNode }) {
|
|
45
|
+
return <div className={props.config.theme}>{props.children}</div>;
|
|
46
|
+
};
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Examples of **correct** code for this rule:
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
// Using interface for complex props
|
|
53
|
+
interface ComponentProps {
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
title: string;
|
|
56
|
+
onClick: () => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const Component = (props: ComponentProps) => (
|
|
60
|
+
<div onClick={props.onClick}>
|
|
61
|
+
<h1>{props.title}</h1>
|
|
62
|
+
{props.children}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Using interface for nested objects
|
|
67
|
+
interface UserComponentProps {
|
|
68
|
+
user: {
|
|
69
|
+
name: string;
|
|
70
|
+
age: number;
|
|
71
|
+
};
|
|
72
|
+
isActive: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const Component = (props: UserComponentProps) => <div>{props.user.name}</div>;
|
|
76
|
+
|
|
77
|
+
// Using type alias is also acceptable
|
|
78
|
+
type ListComponentProps = {
|
|
79
|
+
items: string[];
|
|
80
|
+
title: string;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const Component = (props: ListComponentProps) => (
|
|
84
|
+
<div>
|
|
85
|
+
<h1>{props.title}</h1>
|
|
86
|
+
{props.items.map((item) => (
|
|
87
|
+
<span key={item}>{item}</span>
|
|
88
|
+
))}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// Simple inline types are allowed (2 or fewer properties, no complex types)
|
|
93
|
+
const Component = (props: { children: ReactNode }) => <div>{props.children}</div>;
|
|
94
|
+
|
|
95
|
+
const Component = (props: { title: string; onClick: () => void }) => <div onClick={props.onClick}>{props.title}</div>;
|
|
96
|
+
|
|
97
|
+
// Non-React functions are ignored
|
|
98
|
+
const helper = (props: { value: number; name: string; data: object }) => {
|
|
99
|
+
return props.value + props.name.length;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Functions with no parameters
|
|
103
|
+
const Component = () => <div>Hello</div>;
|
|
104
|
+
|
|
105
|
+
// Functions with multiple parameters
|
|
106
|
+
const Component = (props: { title: string }, ref: any) => <div>{props.title}</div>;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Why?
|
|
110
|
+
|
|
111
|
+
### Benefits of interface declarations:
|
|
112
|
+
|
|
113
|
+
1. **Reusability**: Interfaces can be reused across multiple components
|
|
114
|
+
2. **Better organization**: Separates type definitions from component logic
|
|
115
|
+
3. **Improved readability**: Makes component signatures cleaner and easier to understand
|
|
116
|
+
4. **Better IDE support**: Enhanced autocomplete, refactoring, and navigation
|
|
117
|
+
5. **Documentation**: Interfaces serve as clear documentation of component APIs
|
|
118
|
+
6. **Extensibility**: Interfaces can be extended and composed more easily
|
|
119
|
+
|
|
120
|
+
## Rule Scope
|
|
121
|
+
|
|
122
|
+
This rule applies to:
|
|
123
|
+
|
|
124
|
+
- React functional components (arrow functions, function expressions, function declarations)
|
|
125
|
+
- Functions that return JSX elements or fragments
|
|
126
|
+
- Props with inline type annotations that meet complexity criteria
|
|
127
|
+
|
|
128
|
+
**Complexity criteria:**
|
|
129
|
+
|
|
130
|
+
- More than 2 properties in the type literal
|
|
131
|
+
- Contains nested object types (`{ user: { name: string } }`)
|
|
132
|
+
- Contains array types (`string[]`, `Array<T>`)
|
|
133
|
+
- Contains union types (`'a' | 'b' | 'c'`)
|
|
134
|
+
|
|
135
|
+
The rule ignores:
|
|
136
|
+
|
|
137
|
+
- Non-React functions (functions that don't return JSX)
|
|
138
|
+
- Functions with multiple parameters
|
|
139
|
+
- Functions with no parameters
|
|
140
|
+
- Simple inline types (2 or fewer properties with primitive types)
|
|
141
|
+
- Components already using named types or interfaces
|
|
142
|
+
|
|
143
|
+
## When Not To Use It
|
|
144
|
+
|
|
145
|
+
This rule should not be used if you:
|
|
146
|
+
|
|
147
|
+
- Prefer inline types for consistency across your codebase
|
|
148
|
+
- Are working with very simple components that don't benefit from interface extraction
|
|
149
|
+
- Have specific naming conventions that conflict with interface declarations
|
|
150
|
+
- Are maintaining legacy code with established patterns
|
|
151
|
+
|
|
152
|
+
## Configuration
|
|
153
|
+
|
|
154
|
+
This rule is included in the following configurations:
|
|
155
|
+
|
|
156
|
+
- `nextfriday/react`
|
|
157
|
+
- `nextfriday/react/recommended`
|
|
158
|
+
- `nextfriday/nextjs`
|
|
159
|
+
- `nextfriday/nextjs/recommended`
|
|
160
|
+
|
|
161
|
+
To enable this rule manually:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"rules": {
|
|
166
|
+
"nextfriday/prefer-interface-over-inline-types": "error"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Examples of Complexity Detection
|
|
172
|
+
|
|
173
|
+
### Simple types (allowed as inline)
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
// ✅ Simple - only 1 property
|
|
177
|
+
const Component = (props: { children: ReactNode }) => <div>{props.children}</div>;
|
|
178
|
+
|
|
179
|
+
// ✅ Simple - only 2 properties with primitive types
|
|
180
|
+
const Component = (props: { title: string; count: number }) => (
|
|
181
|
+
<div>
|
|
182
|
+
{props.title}: {props.count}
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Complex types (should use interface)
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
// ❌ Complex - more than 2 properties
|
|
191
|
+
const Component = (props: { title: string; count: number; isActive: boolean }) => <div>...</div>;
|
|
192
|
+
|
|
193
|
+
// ❌ Complex - nested object
|
|
194
|
+
const Component = (props: { user: { name: string }; isActive: boolean }) => <div>...</div>;
|
|
195
|
+
|
|
196
|
+
// ❌ Complex - array type
|
|
197
|
+
const Component = (props: { items: string[]; title: string }) => <div>...</div>;
|
|
198
|
+
|
|
199
|
+
// ❌ Complex - union type
|
|
200
|
+
const Component = (props: { status: "loading" | "success"; message: string }) => <div>...</div>;
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Compatibility
|
|
204
|
+
|
|
205
|
+
- React 16.8+ (functional components)
|
|
206
|
+
- TypeScript 3.0+ (interface declarations)
|
|
207
|
+
- ESLint 9+ with flat config
|
|
208
|
+
|
|
209
|
+
## Version
|
|
210
|
+
|
|
211
|
+
This rule was introduced in eslint-plugin-nextfriday v1.2.0.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# prefer-react-import-types
|
|
2
|
+
|
|
3
|
+
Enforce importing React types and utilities from 'react' instead of using React.X notation.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule enforces direct imports of React types and utilities instead of using the React namespace notation (`React.ReactNode`, `React.useState`, etc.). This promotes cleaner imports and better tree-shaking in modern bundlers.
|
|
8
|
+
|
|
9
|
+
Examples of **incorrect** code for this rule:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
// Types with React namespace
|
|
13
|
+
const Component = (props: { children: React.ReactNode }) => <div>{props.children}</div>;
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
title: React.ReactElement;
|
|
17
|
+
onClick: React.MouseEventHandler;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const MyComponent: React.FC<Props> = ({ title, onClick }) => <div onClick={onClick}>{title}</div>;
|
|
21
|
+
|
|
22
|
+
// Hooks with React namespace
|
|
23
|
+
const Component = () => {
|
|
24
|
+
const [state, setState] = React.useState(0);
|
|
25
|
+
const value = React.useMemo(() => state * 2, [state]);
|
|
26
|
+
const ref = React.useRef<HTMLDivElement>(null);
|
|
27
|
+
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
console.log("mounted");
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
return <div ref={ref}>{value}</div>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Utilities with React namespace
|
|
36
|
+
const element = React.createElement("div", null, "Hello");
|
|
37
|
+
const MemoizedComponent = React.memo(() => <div>Hello</div>);
|
|
38
|
+
const LazyComponent = React.lazy(() => import("./Component"));
|
|
39
|
+
|
|
40
|
+
const MyFragment = () => (
|
|
41
|
+
<React.Fragment>
|
|
42
|
+
<div>Item 1</div>
|
|
43
|
+
<div>Item 2</div>
|
|
44
|
+
</React.Fragment>
|
|
45
|
+
);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Examples of **correct** code for this rule:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// Direct type imports
|
|
52
|
+
import type { ReactNode, ReactElement, MouseEventHandler, FC } from "react";
|
|
53
|
+
|
|
54
|
+
const Component = (props: { children: ReactNode }) => <div>{props.children}</div>;
|
|
55
|
+
|
|
56
|
+
interface Props {
|
|
57
|
+
title: ReactElement;
|
|
58
|
+
onClick: MouseEventHandler;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const MyComponent: FC<Props> = ({ title, onClick }) => <div onClick={onClick}>{title}</div>;
|
|
62
|
+
|
|
63
|
+
// Direct hook imports
|
|
64
|
+
import { useState, useMemo, useRef, useEffect } from "react";
|
|
65
|
+
|
|
66
|
+
const Component = () => {
|
|
67
|
+
const [state, setState] = useState(0);
|
|
68
|
+
const value = useMemo(() => state * 2, [state]);
|
|
69
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
console.log("mounted");
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
return <div ref={ref}>{value}</div>;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Direct utility imports
|
|
79
|
+
import { createElement, memo, lazy, Fragment } from "react";
|
|
80
|
+
|
|
81
|
+
const element = createElement("div", null, "Hello");
|
|
82
|
+
const MemoizedComponent = memo(() => <div>Hello</div>);
|
|
83
|
+
const LazyComponent = lazy(() => import("./Component"));
|
|
84
|
+
|
|
85
|
+
const MyFragment = () => (
|
|
86
|
+
<Fragment>
|
|
87
|
+
<div>Item 1</div>
|
|
88
|
+
<div>Item 2</div>
|
|
89
|
+
</Fragment>
|
|
90
|
+
);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Why?
|
|
94
|
+
|
|
95
|
+
### Benefits of direct imports
|
|
96
|
+
|
|
97
|
+
1. **Better tree-shaking**: Bundlers can more easily eliminate unused code when imports are explicit
|
|
98
|
+
2. **Cleaner code**: Reduces namespace pollution and makes dependencies more explicit
|
|
99
|
+
3. **Improved IDE support**: Better autocomplete and refactoring capabilities
|
|
100
|
+
4. **Smaller bundle sizes**: Only import what you actually use
|
|
101
|
+
5. **TypeScript optimization**: Better type checking and inference with explicit imports
|
|
102
|
+
6. **Modern practices**: Aligns with current React ecosystem conventions
|
|
103
|
+
|
|
104
|
+
## Automatic Fixing
|
|
105
|
+
|
|
106
|
+
This rule provides automatic fixing that replaces `React.X` with the direct import name. However, you will need to manually add the appropriate import statements:
|
|
107
|
+
|
|
108
|
+
- **Types**: Use `import type { TypeName } from "react"`
|
|
109
|
+
- **Runtime code**: Use `import { functionName } from "react"`
|
|
110
|
+
|
|
111
|
+
## Supported React Exports
|
|
112
|
+
|
|
113
|
+
### Types (use `import type`)
|
|
114
|
+
|
|
115
|
+
- `ReactNode`, `ReactElement`, `ReactChildren`, `ReactChild`
|
|
116
|
+
- `ComponentType`, `FC`, `FunctionComponent`, `Component`, `PureComponent`
|
|
117
|
+
- Event handlers: `ReactEventHandler`, `MouseEventHandler`, `ChangeEventHandler`, etc.
|
|
118
|
+
- Refs: `RefObject`, `MutableRefObject`, `Ref`, `ForwardedRef`
|
|
119
|
+
- Props: `HTMLProps`, `ComponentProps`
|
|
120
|
+
- `JSXElementConstructor`
|
|
121
|
+
|
|
122
|
+
### Runtime Exports (use `import`)
|
|
123
|
+
|
|
124
|
+
#### Hooks
|
|
125
|
+
|
|
126
|
+
- `useState`, `useEffect`, `useContext`, `useReducer`
|
|
127
|
+
- `useCallback`, `useMemo`, `useRef`, `useImperativeHandle`
|
|
128
|
+
- `useLayoutEffect`, `useDebugValue`, `useDeferredValue`
|
|
129
|
+
- `useTransition`, `useId`, `useSyncExternalStore`, `useInsertionEffect`
|
|
130
|
+
|
|
131
|
+
#### Utilities
|
|
132
|
+
|
|
133
|
+
- `createElement`, `createContext`, `forwardRef`, `memo`, `lazy`
|
|
134
|
+
- `Suspense`, `Fragment`, `StrictMode`, `createRef`
|
|
135
|
+
- `isValidElement`, `cloneElement`, `Children`
|
|
136
|
+
|
|
137
|
+
## When Not To Use It
|
|
138
|
+
|
|
139
|
+
This rule should not be used if you:
|
|
140
|
+
|
|
141
|
+
- Prefer the React namespace for consistency across a large codebase
|
|
142
|
+
- Are working with legacy code that heavily uses React namespace
|
|
143
|
+
- Need to maintain compatibility with older bundlers that don't support tree-shaking
|
|
144
|
+
|
|
145
|
+
## Configuration
|
|
146
|
+
|
|
147
|
+
This rule is included in the following configurations:
|
|
148
|
+
|
|
149
|
+
- `nextfriday/base`
|
|
150
|
+
- `nextfriday/base/recommended`
|
|
151
|
+
- `nextfriday/react`
|
|
152
|
+
- `nextfriday/react/recommended`
|
|
153
|
+
- `nextfriday/nextjs`
|
|
154
|
+
- `nextfriday/nextjs/recommended`
|
|
155
|
+
|
|
156
|
+
To enable this rule manually:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"rules": {
|
|
161
|
+
"nextfriday/prefer-react-import-types": "error"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Compatibility
|
|
167
|
+
|
|
168
|
+
- React 16.8+ (hooks support)
|
|
169
|
+
- TypeScript 3.8+ (type-only imports)
|
|
170
|
+
- Modern bundlers with tree-shaking support
|
|
171
|
+
- ESLint 9+ with flat config
|
|
172
|
+
|
|
173
|
+
## Version
|
|
174
|
+
|
|
175
|
+
This rule was introduced in eslint-plugin-nextfriday v1.1.0.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# react-props-destructure
|
|
2
|
+
|
|
3
|
+
Enforce destructuring props inside React component body instead of parameters.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule enforces a consistent pattern for handling props in React components by requiring destructuring to be done inside the component body rather than in the parameter list. This promotes better code readability and makes prop usage more explicit.
|
|
8
|
+
|
|
9
|
+
Examples of **incorrect** code for this rule:
|
|
10
|
+
|
|
11
|
+
```jsx
|
|
12
|
+
const Component = ({ children }) => <div>{children}</div>;
|
|
13
|
+
|
|
14
|
+
const Component = ({ title, children, onClick }) => (
|
|
15
|
+
<div onClick={onClick}>
|
|
16
|
+
<h1>{title}</h1>
|
|
17
|
+
{children}
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
function Component({ children }) {
|
|
22
|
+
return <div>{children}</div>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const Component = function ({ children }) {
|
|
26
|
+
return <div>{children}</div>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Also applies to conditional returns
|
|
30
|
+
const Component = ({ show, children }) => {
|
|
31
|
+
return show ? <div>{children}</div> : null;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// And logical operators
|
|
35
|
+
const Component = ({ show, children }) => {
|
|
36
|
+
return show && <div>{children}</div>;
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Examples of **correct** code for this rule:
|
|
41
|
+
|
|
42
|
+
```jsx
|
|
43
|
+
const Component = (props) => {
|
|
44
|
+
const { children } = props;
|
|
45
|
+
return <div>{children}</div>;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const Component = (props) => {
|
|
49
|
+
const { title, children, onClick } = props;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div onClick={onClick}>
|
|
53
|
+
<h1>{title}</h1>
|
|
54
|
+
{children}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function Component(props) {
|
|
60
|
+
const { children } = props;
|
|
61
|
+
return <div>{children}</div>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const Component = function (props) {
|
|
65
|
+
const { children } = props;
|
|
66
|
+
return <div>{children}</div>;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Multiple parameters are allowed
|
|
70
|
+
const Component = (props, ref) => {
|
|
71
|
+
return <div>{props.children}</div>;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// No parameters is allowed
|
|
75
|
+
const Component = () => {
|
|
76
|
+
return <div>Hello</div>;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Already using props parameter (no destructuring) is allowed
|
|
80
|
+
const Component = (props) => {
|
|
81
|
+
return <div>{props.children}</div>;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Non-React functions are ignored
|
|
85
|
+
const helper = ({ value }) => {
|
|
86
|
+
return value * 2;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const regularFunction = ({ data }) => {
|
|
90
|
+
return data.map((item) => item.id);
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Why?
|
|
95
|
+
|
|
96
|
+
### Benefits of destructuring inside component body
|
|
97
|
+
|
|
98
|
+
1. **Explicit prop usage**: Makes it clear which props are being used within the component
|
|
99
|
+
2. **Better readability**: Separates prop extraction from component signature
|
|
100
|
+
3. **Easier refactoring**: Props can be easily modified without changing the function signature
|
|
101
|
+
4. **Consistent patterns**: Promotes a uniform approach across the codebase
|
|
102
|
+
5. **Better TypeScript integration**: Works better with prop type definitions
|
|
103
|
+
|
|
104
|
+
## When Not To Use It
|
|
105
|
+
|
|
106
|
+
This rule should not be used if you:
|
|
107
|
+
|
|
108
|
+
- Prefer parameter destructuring for brevity
|
|
109
|
+
- Are working on a codebase that already consistently uses parameter destructuring
|
|
110
|
+
- Need to maintain compatibility with existing patterns
|
|
111
|
+
|
|
112
|
+
## Rule Scope
|
|
113
|
+
|
|
114
|
+
This rule only applies to:
|
|
115
|
+
|
|
116
|
+
- Functions that return JSX elements or fragments
|
|
117
|
+
- Functions with exactly one parameter that is object destructuring
|
|
118
|
+
- Arrow functions, function expressions, and function declarations
|
|
119
|
+
|
|
120
|
+
The rule ignores:
|
|
121
|
+
|
|
122
|
+
- Non-React functions (functions that don't return JSX)
|
|
123
|
+
- Functions with multiple parameters
|
|
124
|
+
- Functions with no parameters
|
|
125
|
+
- Functions already using a `props` parameter without destructuring
|
|
126
|
+
|
|
127
|
+
## Configuration
|
|
128
|
+
|
|
129
|
+
This rule is included in the following configurations:
|
|
130
|
+
|
|
131
|
+
- `nextfriday/react`
|
|
132
|
+
- `nextfriday/react/recommended`
|
|
133
|
+
- `nextfriday/nextjs`
|
|
134
|
+
- `nextfriday/nextjs/recommended`
|
|
135
|
+
|
|
136
|
+
To enable this rule manually:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"rules": {
|
|
141
|
+
"nextfriday/react-props-destructure": "error"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Compatibility
|
|
147
|
+
|
|
148
|
+
- React functional components
|
|
149
|
+
- Arrow functions with JSX
|
|
150
|
+
- Function declarations with JSX
|
|
151
|
+
- Function expressions with JSX
|
|
152
|
+
- Conditional JSX returns
|
|
153
|
+
- Logical operator JSX returns
|
|
154
|
+
- JSX fragments
|
|
155
|
+
|
|
156
|
+
## Version
|
|
157
|
+
|
|
158
|
+
This rule was introduced in eslint-plugin-nextfriday v1.0.0.
|