@the-bearded-bear/claude-craft 8.8.1 → 8.8.2
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/Dev/i18n/de/Angular/commands/check-compliance.md +218 -168
- package/Dev/i18n/de/Common/agents/refactoring-specialist.md +146 -69
- package/Dev/i18n/de/Common/commands/add-technology.md +166 -68
- package/Dev/i18n/de/Common/commands/setup-ci.md +216 -33
- package/Dev/i18n/de/Laravel/commands/check-compliance.md +223 -115
- package/Dev/i18n/de/Python/checklists/new-feature.md +319 -44
- package/Dev/i18n/de/React/rules/02-architecture.md +483 -322
- package/Dev/i18n/de/React/rules/03-coding-standards.md +584 -368
- package/Dev/i18n/de/Symfony/commands/check-compliance.md +186 -114
- package/Dev/i18n/de/Symfony/rules/07-testing-symfony.md +679 -10
- package/Dev/i18n/de/UIUX/commands/a11y-component.md +284 -26
- package/Dev/i18n/de/UIUX/commands/design-tokens.md +199 -35
- package/Dev/i18n/de/UIUX/commands/user-flow.md +179 -16
- package/Dev/i18n/de/VueJS/commands/check-compliance.md +227 -102
- package/Dev/i18n/es/Angular/commands/check-compliance.md +217 -167
- package/Dev/i18n/es/Common/commands/add-technology.md +158 -60
- package/Dev/i18n/es/Laravel/commands/check-compliance.md +223 -115
- package/Dev/i18n/es/React/commands/check-testing.md +263 -169
- package/Dev/i18n/es/ReactNative/commands/check-testing.md +256 -198
- package/Dev/i18n/es/Symfony/commands/check-compliance.md +189 -117
- package/Dev/i18n/es/Symfony/commands/check-testing.md +301 -102
- package/Dev/i18n/es/Symfony/commands/migration-plan.md +267 -34
- package/Dev/i18n/es/UIUX/commands/a11y-component.md +274 -16
- package/Dev/i18n/es/UIUX/commands/design-tokens.md +186 -22
- package/Dev/i18n/es/UIUX/commands/user-flow.md +173 -10
- package/Dev/i18n/es/VueJS/commands/check-compliance.md +227 -102
- package/Dev/i18n/fr/Angular/commands/check-compliance.md +217 -167
- package/Dev/i18n/fr/Common/commands/ralph-run.md +138 -60
- package/Dev/i18n/fr/Laravel/commands/check-compliance.md +223 -115
- package/Dev/i18n/fr/React/commands/check-architecture.md +370 -53
- package/Dev/i18n/fr/React/commands/check-code-quality.md +454 -64
- package/Dev/i18n/fr/React/commands/check-testing.md +476 -102
- package/Dev/i18n/fr/Symfony/commands/check-compliance.md +188 -116
- package/Dev/i18n/fr/VueJS/commands/check-compliance.md +227 -102
- package/Dev/i18n/pt/Angular/commands/check-compliance.md +225 -175
- package/Dev/i18n/pt/Common/agents/ralph-conductor.md +211 -30
- package/Dev/i18n/pt/Common/commands/add-technology.md +149 -51
- package/Dev/i18n/pt/Common/commands/ralph-run.md +239 -35
- package/Dev/i18n/pt/Flutter/commands/analyze-performance.md +331 -46
- package/Dev/i18n/pt/Flutter/commands/check-compliance.md +234 -29
- package/Dev/i18n/pt/Flutter/commands/generate-feature.md +526 -51
- package/Dev/i18n/pt/Flutter/commands/generate-widget.md +515 -27
- package/Dev/i18n/pt/Flutter/commands/golden-update.md +322 -46
- package/Dev/i18n/pt/Flutter/commands/localization-check.md +278 -37
- package/Dev/i18n/pt/Laravel/commands/check-compliance.md +212 -104
- package/Dev/i18n/pt/React/commands/accessibility-check.md +151 -42
- package/Dev/i18n/pt/React/commands/bundle-analyze.md +300 -25
- package/Dev/i18n/pt/React/commands/check-architecture.md +369 -34
- package/Dev/i18n/pt/React/commands/check-code-quality.md +440 -34
- package/Dev/i18n/pt/React/commands/check-compliance.md +232 -62
- package/Dev/i18n/pt/React/commands/check-security.md +370 -31
- package/Dev/i18n/pt/React/commands/check-testing.md +473 -43
- package/Dev/i18n/pt/React/commands/generate-component.md +454 -19
- package/Dev/i18n/pt/React/commands/generate-hook.md +425 -24
- package/Dev/i18n/pt/React/commands/storybook-story.md +520 -35
- package/Dev/i18n/pt/ReactNative/commands/app-size.md +358 -387
- package/Dev/i18n/pt/ReactNative/commands/check-code-quality.md +246 -75
- package/Dev/i18n/pt/ReactNative/commands/check-compliance.md +191 -85
- package/Dev/i18n/pt/ReactNative/commands/check-security.md +363 -115
- package/Dev/i18n/pt/ReactNative/commands/check-testing.md +269 -79
- package/Dev/i18n/pt/ReactNative/commands/generate-screen.md +491 -324
- package/Dev/i18n/pt/ReactNative/commands/native-module.md +539 -82
- package/Dev/i18n/pt/ReactNative/commands/store-prepare.md +429 -185
- package/Dev/i18n/pt/ReactNative/rules/02-architecture.md +1084 -31
- package/Dev/i18n/pt/Symfony/commands/check-compliance.md +195 -123
- package/Dev/i18n/pt/UIUX/commands/a11y-audit.md +208 -24
- package/Dev/i18n/pt/UIUX/commands/a11y-component.md +281 -23
- package/Dev/i18n/pt/UIUX/commands/design-tokens.md +197 -33
- package/Dev/i18n/pt/UIUX/commands/user-flow.md +183 -20
- package/Dev/i18n/pt/VueJS/commands/check-compliance.md +228 -103
- package/Dev/i18n/pt/Workflow/commands/analyze.md +147 -146
- package/Dev/i18n/pt/Workflow/commands/design.md +205 -204
- package/Dev/i18n/pt/Workflow/commands/implement.md +184 -184
- package/Project/i18n/de/Sprint/commands/dev.md +339 -86
- package/Project/i18n/es/Sprint/commands/dev.md +342 -91
- package/Project/i18n/pt/Sprint/commands/dev.md +343 -92
- package/bundles/cursor/.cursorrules +1 -1
- package/bundles/windsurf/.windsurfrules +1 -1
- package/package.json +1 -1
|
@@ -1,500 +1,716 @@
|
|
|
1
|
-
# Coding
|
|
1
|
+
# React TypeScript Coding Standards
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
### Komponenten
|
|
3
|
+
## TypeScript Strict Mode
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
// ✅ GUT - PascalCase für Komponenten
|
|
9
|
-
export const UserProfile: FC = () => { };
|
|
10
|
-
export const LoginForm: FC = () => { };
|
|
5
|
+
### tsconfig.json-Konfiguration
|
|
11
6
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"compilerOptions": {
|
|
10
|
+
// Strikte Typprüfungsoptionen
|
|
11
|
+
"strict": true,
|
|
12
|
+
"noImplicitAny": true,
|
|
13
|
+
"strictNullChecks": true,
|
|
14
|
+
"strictFunctionTypes": true,
|
|
15
|
+
"strictBindCallApply": true,
|
|
16
|
+
"strictPropertyInitialization": true,
|
|
17
|
+
"noImplicitThis": true,
|
|
18
|
+
"alwaysStrict": true,
|
|
19
|
+
|
|
20
|
+
// Zusätzliche Prüfungen
|
|
21
|
+
"noUnusedLocals": true,
|
|
22
|
+
"noUnusedParameters": true,
|
|
23
|
+
"noImplicitReturns": true,
|
|
24
|
+
"noFallthroughCasesInSwitch": true,
|
|
25
|
+
"noUncheckedIndexedAccess": true,
|
|
26
|
+
"noImplicitOverride": true,
|
|
27
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
28
|
+
|
|
29
|
+
// Modulauflösung
|
|
30
|
+
"moduleResolution": "bundler",
|
|
31
|
+
"resolveJsonModule": true,
|
|
32
|
+
"allowImportingTsExtensions": true,
|
|
33
|
+
"isolatedModules": true,
|
|
34
|
+
"esModuleInterop": true,
|
|
35
|
+
|
|
36
|
+
// Ausgabe
|
|
37
|
+
"declaration": true,
|
|
38
|
+
"declarationMap": true,
|
|
39
|
+
"sourceMap": true,
|
|
40
|
+
"removeComments": false,
|
|
41
|
+
|
|
42
|
+
// React
|
|
43
|
+
"jsx": "react-jsx",
|
|
44
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
45
|
+
"target": "ES2020",
|
|
46
|
+
"module": "ESNext",
|
|
47
|
+
|
|
48
|
+
// Pfade
|
|
49
|
+
"baseUrl": ".",
|
|
50
|
+
"paths": {
|
|
51
|
+
"@/*": ["./src/*"]
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"include": ["src"],
|
|
55
|
+
"exclude": ["node_modules", "dist", "build"]
|
|
56
|
+
}
|
|
15
57
|
```
|
|
16
58
|
|
|
17
|
-
###
|
|
59
|
+
### Strikte TypeScript-Regeln
|
|
60
|
+
|
|
61
|
+
#### 1. Explizite Typen
|
|
18
62
|
|
|
19
63
|
```typescript
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
64
|
+
// ❌ Schlecht – Impliziter 'any'-Typ
|
|
65
|
+
const handleClick = (event) => {
|
|
66
|
+
console.log(event.target);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// ✅ Gut – Expliziter Typ
|
|
70
|
+
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
|
|
71
|
+
console.log(event.currentTarget);
|
|
72
|
+
};
|
|
23
73
|
|
|
24
|
-
// ❌
|
|
25
|
-
|
|
26
|
-
|
|
74
|
+
// ❌ Schlecht – Impliziter Rückgabetyp
|
|
75
|
+
function calculateTotal(items) {
|
|
76
|
+
return items.reduce((sum, item) => sum + item.price, 0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ✅ Gut – Explizite Typen
|
|
80
|
+
function calculateTotal(items: Product[]): number {
|
|
81
|
+
return items.reduce((sum, item) => sum + item.price, 0);
|
|
82
|
+
}
|
|
27
83
|
```
|
|
28
84
|
|
|
29
|
-
|
|
85
|
+
#### 2. Null-Sicherheit
|
|
30
86
|
|
|
31
87
|
```typescript
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
88
|
+
// ❌ Schlecht – Keine Null-Prüfung
|
|
89
|
+
function getUserName(user: User) {
|
|
90
|
+
return user.profile.name; // Fehler wenn profile null ist
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ✅ Gut – Optionales Verketten
|
|
94
|
+
function getUserName(user: User): string {
|
|
95
|
+
return user.profile?.name ?? 'Anonym';
|
|
96
|
+
}
|
|
35
97
|
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
98
|
+
// ✅ Gut – Guard-Klausel
|
|
99
|
+
function getUserName(user: User): string {
|
|
100
|
+
if (!user.profile) {
|
|
101
|
+
return 'Anonym';
|
|
102
|
+
}
|
|
103
|
+
return user.profile.name;
|
|
104
|
+
}
|
|
39
105
|
```
|
|
40
106
|
|
|
41
|
-
|
|
107
|
+
#### 3. Union-Typen und Type Guards
|
|
42
108
|
|
|
43
109
|
```typescript
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
UserProfile.tsx
|
|
110
|
+
// Union-Typen definieren
|
|
111
|
+
type Status = 'idle' | 'loading' | 'success' | 'error';
|
|
47
112
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
113
|
+
interface IdleState {
|
|
114
|
+
status: 'idle';
|
|
115
|
+
}
|
|
51
116
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
117
|
+
interface LoadingState {
|
|
118
|
+
status: 'loading';
|
|
119
|
+
}
|
|
55
120
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
121
|
+
interface SuccessState {
|
|
122
|
+
status: 'success';
|
|
123
|
+
data: User;
|
|
124
|
+
}
|
|
60
125
|
|
|
61
|
-
|
|
126
|
+
interface ErrorState {
|
|
127
|
+
status: 'error';
|
|
128
|
+
error: Error;
|
|
129
|
+
}
|
|
62
130
|
|
|
63
|
-
|
|
131
|
+
type AsyncState = IdleState | LoadingState | SuccessState | ErrorState;
|
|
64
132
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
id: string;
|
|
69
|
-
name: string;
|
|
70
|
-
email: string;
|
|
71
|
-
role: 'admin' | 'user';
|
|
133
|
+
// Type Guards
|
|
134
|
+
function isSuccessState(state: AsyncState): state is SuccessState {
|
|
135
|
+
return state.status === 'success';
|
|
72
136
|
}
|
|
73
137
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
138
|
+
function isErrorState(state: AsyncState): state is ErrorState {
|
|
139
|
+
return state.status === 'error';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Verwendung
|
|
143
|
+
const renderState = (state: AsyncState) => {
|
|
144
|
+
if (isSuccessState(state)) {
|
|
145
|
+
return <div>{state.data.name}</div>; // TypeScript weiß, dass data existiert
|
|
146
|
+
}
|
|
78
147
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
148
|
+
if (isErrorState(state)) {
|
|
149
|
+
return <div>{state.error.message}</div>; // TypeScript weiß, dass error existiert
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return <Spinner />;
|
|
83
153
|
};
|
|
84
154
|
```
|
|
85
155
|
|
|
86
|
-
|
|
156
|
+
## ESLint-Konfiguration
|
|
87
157
|
|
|
88
|
-
|
|
89
|
-
// ✅ Interface für Objekt-Shapes (erweiterbar)
|
|
90
|
-
interface User {
|
|
91
|
-
id: string;
|
|
92
|
-
name: string;
|
|
93
|
-
}
|
|
158
|
+
### Installation
|
|
94
159
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
160
|
+
```bash
|
|
161
|
+
npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
|
|
162
|
+
npm install -D eslint-plugin-react eslint-plugin-react-hooks
|
|
163
|
+
npm install -D eslint-plugin-jsx-a11y eslint-plugin-import
|
|
164
|
+
npm install -D eslint-config-prettier
|
|
165
|
+
```
|
|
98
166
|
|
|
99
|
-
|
|
100
|
-
type Status = 'pending' | 'approved' | 'rejected';
|
|
101
|
-
type ID = string | number;
|
|
102
|
-
type UserWithRole = User & { role: string };
|
|
167
|
+
### .eslintrc.cjs-Konfiguration
|
|
103
168
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
169
|
+
```javascript
|
|
170
|
+
module.exports = {
|
|
171
|
+
root: true,
|
|
172
|
+
env: {
|
|
173
|
+
browser: true,
|
|
174
|
+
es2020: true,
|
|
175
|
+
node: true
|
|
176
|
+
},
|
|
177
|
+
extends: [
|
|
178
|
+
'eslint:recommended',
|
|
179
|
+
'plugin:@typescript-eslint/recommended',
|
|
180
|
+
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
|
181
|
+
'plugin:react/recommended',
|
|
182
|
+
'plugin:react/jsx-runtime',
|
|
183
|
+
'plugin:react-hooks/recommended',
|
|
184
|
+
'plugin:jsx-a11y/recommended',
|
|
185
|
+
'plugin:import/recommended',
|
|
186
|
+
'plugin:import/typescript',
|
|
187
|
+
'prettier'
|
|
188
|
+
],
|
|
189
|
+
parser: '@typescript-eslint/parser',
|
|
190
|
+
parserOptions: {
|
|
191
|
+
ecmaVersion: 'latest',
|
|
192
|
+
sourceType: 'module',
|
|
193
|
+
project: ['./tsconfig.json'],
|
|
194
|
+
ecmaFeatures: {
|
|
195
|
+
jsx: true
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
plugins: ['react', 'react-hooks', '@typescript-eslint', 'jsx-a11y', 'import'],
|
|
199
|
+
settings: {
|
|
200
|
+
react: {
|
|
201
|
+
version: 'detect'
|
|
202
|
+
},
|
|
203
|
+
'import/resolver': {
|
|
204
|
+
typescript: {
|
|
205
|
+
alwaysTryTypes: true,
|
|
206
|
+
project: './tsconfig.json'
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
rules: {
|
|
211
|
+
// TypeScript
|
|
212
|
+
'@typescript-eslint/no-unused-vars': [
|
|
213
|
+
'error',
|
|
214
|
+
{
|
|
215
|
+
argsIgnorePattern: '^_',
|
|
216
|
+
varsIgnorePattern: '^_'
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
'@typescript-eslint/no-explicit-any': 'error',
|
|
220
|
+
'@typescript-eslint/explicit-function-return-type': [
|
|
221
|
+
'warn',
|
|
222
|
+
{
|
|
223
|
+
allowExpressions: true,
|
|
224
|
+
allowTypedFunctionExpressions: true
|
|
225
|
+
}
|
|
226
|
+
],
|
|
227
|
+
'@typescript-eslint/no-non-null-assertion': 'error',
|
|
228
|
+
'@typescript-eslint/prefer-nullish-coalescing': 'error',
|
|
229
|
+
'@typescript-eslint/prefer-optional-chain': 'error',
|
|
230
|
+
'@typescript-eslint/consistent-type-imports': [
|
|
231
|
+
'error',
|
|
232
|
+
{
|
|
233
|
+
prefer: 'type-imports'
|
|
234
|
+
}
|
|
235
|
+
],
|
|
236
|
+
|
|
237
|
+
// React
|
|
238
|
+
'react/prop-types': 'off',
|
|
239
|
+
'react/react-in-jsx-scope': 'off',
|
|
240
|
+
'react/jsx-no-target-blank': 'error',
|
|
241
|
+
'react/jsx-curly-brace-presence': [
|
|
242
|
+
'error',
|
|
243
|
+
{
|
|
244
|
+
props: 'never',
|
|
245
|
+
children: 'never'
|
|
246
|
+
}
|
|
247
|
+
],
|
|
248
|
+
'react/self-closing-comp': 'error',
|
|
249
|
+
'react/jsx-boolean-value': ['error', 'never'],
|
|
250
|
+
'react/jsx-fragments': ['error', 'syntax'],
|
|
251
|
+
|
|
252
|
+
// React Hooks
|
|
253
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
254
|
+
'react-hooks/exhaustive-deps': 'warn',
|
|
255
|
+
|
|
256
|
+
// Import
|
|
257
|
+
'import/order': [
|
|
258
|
+
'error',
|
|
259
|
+
{
|
|
260
|
+
groups: [
|
|
261
|
+
'builtin',
|
|
262
|
+
'external',
|
|
263
|
+
'internal',
|
|
264
|
+
'parent',
|
|
265
|
+
'sibling',
|
|
266
|
+
'index',
|
|
267
|
+
'type'
|
|
268
|
+
],
|
|
269
|
+
'newlines-between': 'always',
|
|
270
|
+
alphabetize: {
|
|
271
|
+
order: 'asc',
|
|
272
|
+
caseInsensitive: true
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
'import/no-duplicates': 'error',
|
|
277
|
+
'import/no-unresolved': 'error',
|
|
278
|
+
|
|
279
|
+
// Allgemein
|
|
280
|
+
'no-console': ['warn', { allow: ['warn', 'error'] }],
|
|
281
|
+
'prefer-const': 'error',
|
|
282
|
+
'no-var': 'error'
|
|
283
|
+
}
|
|
107
284
|
};
|
|
108
285
|
```
|
|
109
286
|
|
|
110
|
-
|
|
287
|
+
## Prettier-Konfiguration
|
|
111
288
|
|
|
112
|
-
|
|
113
|
-
// ✅ GUT - Wiederverwendbare generische Funktionen
|
|
114
|
-
function useAsync<T>(
|
|
115
|
-
asyncFn: () => Promise<T>
|
|
116
|
-
): {
|
|
117
|
-
data: T | null;
|
|
118
|
-
error: Error | null;
|
|
119
|
-
isLoading: boolean;
|
|
120
|
-
} {
|
|
121
|
-
// Implementation
|
|
122
|
-
}
|
|
289
|
+
### Installation
|
|
123
290
|
|
|
124
|
-
|
|
125
|
-
|
|
291
|
+
```bash
|
|
292
|
+
npm install -D prettier
|
|
126
293
|
```
|
|
127
294
|
|
|
128
|
-
|
|
295
|
+
### .prettierrc-Konfiguration
|
|
129
296
|
|
|
130
|
-
|
|
297
|
+
```json
|
|
298
|
+
{
|
|
299
|
+
"printWidth": 90,
|
|
300
|
+
"tabWidth": 2,
|
|
301
|
+
"useTabs": false,
|
|
302
|
+
"semi": true,
|
|
303
|
+
"singleQuote": true,
|
|
304
|
+
"quoteProps": "as-needed",
|
|
305
|
+
"jsxSingleQuote": false,
|
|
306
|
+
"trailingComma": "none",
|
|
307
|
+
"bracketSpacing": true,
|
|
308
|
+
"bracketSameLine": false,
|
|
309
|
+
"arrowParens": "avoid",
|
|
310
|
+
"endOfLine": "lf",
|
|
311
|
+
"plugins": ["prettier-plugin-tailwindcss"]
|
|
312
|
+
}
|
|
313
|
+
```
|
|
131
314
|
|
|
132
|
-
|
|
133
|
-
// ✅ GUT - Interface mit Dokumentation
|
|
134
|
-
/**
|
|
135
|
-
* User-Karten-Komponente zur Anzeige von Benutzerinformationen
|
|
136
|
-
*/
|
|
137
|
-
interface UserCardProps {
|
|
138
|
-
/**
|
|
139
|
-
* Anzuzeigender Benutzer
|
|
140
|
-
*/
|
|
141
|
-
user: User;
|
|
315
|
+
### .prettierignore
|
|
142
316
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
317
|
+
```
|
|
318
|
+
node_modules
|
|
319
|
+
dist
|
|
320
|
+
build
|
|
321
|
+
.next
|
|
322
|
+
coverage
|
|
323
|
+
*.min.js
|
|
324
|
+
*.min.css
|
|
325
|
+
package-lock.json
|
|
326
|
+
yarn.lock
|
|
327
|
+
pnpm-lock.yaml
|
|
328
|
+
```
|
|
147
329
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
className?: string;
|
|
152
|
-
}
|
|
330
|
+
## Namenskonventionen
|
|
331
|
+
|
|
332
|
+
### 1. Dateien
|
|
153
333
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
334
|
+
```
|
|
335
|
+
✅ React-Komponenten: PascalCase
|
|
336
|
+
- UserProfile.tsx
|
|
337
|
+
- LoginForm.tsx
|
|
338
|
+
- DataTable.tsx
|
|
339
|
+
|
|
340
|
+
✅ Hooks: camelCase mit 'use'-Präfix
|
|
341
|
+
- useAuth.ts
|
|
342
|
+
- useLocalStorage.ts
|
|
343
|
+
- useDebounce.ts
|
|
344
|
+
|
|
345
|
+
✅ Hilfsfunktionen: camelCase
|
|
346
|
+
- formatDate.ts
|
|
347
|
+
- validateEmail.ts
|
|
348
|
+
- calculateTotal.ts
|
|
349
|
+
|
|
350
|
+
✅ Konstanten: UPPER_SNAKE_CASE
|
|
351
|
+
- API_ENDPOINTS.ts
|
|
352
|
+
- VALIDATION_RULES.ts
|
|
353
|
+
- ERROR_MESSAGES.ts
|
|
354
|
+
|
|
355
|
+
✅ Typen: PascalCase mit '.types'-Suffix
|
|
356
|
+
- User.types.ts
|
|
357
|
+
- Product.types.ts
|
|
358
|
+
- api.types.ts
|
|
359
|
+
|
|
360
|
+
✅ Services: camelCase mit '.service'-Suffix
|
|
361
|
+
- auth.service.ts
|
|
362
|
+
- user.service.ts
|
|
363
|
+
- api.service.ts
|
|
364
|
+
|
|
365
|
+
✅ Tests: gleicher Name + '.test' oder '.spec'
|
|
366
|
+
- UserProfile.test.tsx
|
|
367
|
+
- useAuth.test.ts
|
|
368
|
+
- formatDate.spec.ts
|
|
157
369
|
```
|
|
158
370
|
|
|
159
|
-
###
|
|
371
|
+
### 2. Variablen und Funktionen
|
|
160
372
|
|
|
161
373
|
```typescript
|
|
162
|
-
// ✅
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
374
|
+
// ✅ Variablen: camelCase
|
|
375
|
+
const userName = 'John';
|
|
376
|
+
const isAuthenticated = true;
|
|
377
|
+
const userProfile = { name: 'John' };
|
|
378
|
+
|
|
379
|
+
// ✅ Konstanten: UPPER_SNAKE_CASE
|
|
380
|
+
const API_BASE_URL = 'https://api.example.com';
|
|
381
|
+
const MAX_RETRY_ATTEMPTS = 3;
|
|
382
|
+
const DEFAULT_PAGE_SIZE = 10;
|
|
383
|
+
|
|
384
|
+
// ✅ Funktionen: camelCase, Aktionsverb
|
|
385
|
+
function getUserById(id: string): User {}
|
|
386
|
+
function calculateTotal(items: Product[]): number {}
|
|
387
|
+
function validateEmail(email: string): boolean {}
|
|
388
|
+
|
|
389
|
+
// ✅ Handler: 'handle'-Präfix
|
|
390
|
+
const handleClick = () => {};
|
|
391
|
+
const handleSubmit = (e: FormEvent) => {};
|
|
392
|
+
const handleChange = (value: string) => {};
|
|
393
|
+
|
|
394
|
+
// ✅ Boolesche Werte: 'is'-, 'has'-, 'should'-, 'can'-Präfix
|
|
395
|
+
const isLoading = false;
|
|
396
|
+
const hasError = false;
|
|
397
|
+
const shouldRender = true;
|
|
398
|
+
const canEdit = false;
|
|
177
399
|
```
|
|
178
400
|
|
|
179
|
-
###
|
|
401
|
+
### 3. Komponenten
|
|
180
402
|
|
|
181
403
|
```typescript
|
|
182
|
-
// ✅
|
|
183
|
-
const
|
|
184
|
-
const handleSubmit = () => { };
|
|
185
|
-
const handleChange = () => { };
|
|
404
|
+
// ✅ Komponenten: PascalCase
|
|
405
|
+
export const UserProfile: FC<UserProfileProps> = (props) => {};
|
|
186
406
|
|
|
187
|
-
// Props
|
|
188
|
-
interface
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
onChange?: (value: string) => void;
|
|
407
|
+
// ✅ Props-Interface: Komponentenname + 'Props'
|
|
408
|
+
interface UserProfileProps {
|
|
409
|
+
userId: string;
|
|
410
|
+
onUpdate?: (user: User) => void;
|
|
192
411
|
}
|
|
193
|
-
```
|
|
194
412
|
|
|
195
|
-
|
|
413
|
+
// ✅ Hooks: camelCase mit 'use'-Präfix
|
|
414
|
+
export const useUserProfile = (userId: string) => {};
|
|
196
415
|
|
|
197
|
-
|
|
416
|
+
// ✅ Typen: PascalCase
|
|
417
|
+
type User = {
|
|
418
|
+
id: string;
|
|
419
|
+
name: string;
|
|
420
|
+
};
|
|
198
421
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
422
|
+
// ✅ Interfaces: PascalCase (optionales 'I'-Präfix)
|
|
423
|
+
interface IUser {
|
|
424
|
+
id: string;
|
|
425
|
+
name: string;
|
|
426
|
+
}
|
|
204
427
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
428
|
+
// ✅ Enums: PascalCase
|
|
429
|
+
enum UserRole {
|
|
430
|
+
ADMIN = 'admin',
|
|
431
|
+
USER = 'user',
|
|
432
|
+
GUEST = 'guest'
|
|
433
|
+
}
|
|
434
|
+
```
|
|
208
435
|
|
|
209
|
-
|
|
210
|
-
const { data, isLoading } = useUsers();
|
|
436
|
+
## Komponentenmuster
|
|
211
437
|
|
|
212
|
-
|
|
213
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
438
|
+
### 1. Funktionale Komponente mit TypeScript
|
|
214
439
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const handleClick = useCallback(() => {}, []);
|
|
440
|
+
```typescript
|
|
441
|
+
import { FC } from 'react';
|
|
218
442
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
443
|
+
// Props-Interface
|
|
444
|
+
interface ButtonProps {
|
|
445
|
+
variant?: 'primary' | 'secondary';
|
|
446
|
+
size?: 'sm' | 'md' | 'lg';
|
|
447
|
+
disabled?: boolean;
|
|
448
|
+
onClick?: () => void;
|
|
449
|
+
children: React.ReactNode;
|
|
450
|
+
}
|
|
223
451
|
|
|
224
|
-
|
|
225
|
-
|
|
452
|
+
// Funktionale Komponente mit FC
|
|
453
|
+
export const Button: FC<ButtonProps> = ({
|
|
454
|
+
variant = 'primary',
|
|
455
|
+
size = 'md',
|
|
456
|
+
disabled = false,
|
|
457
|
+
onClick,
|
|
458
|
+
children
|
|
459
|
+
}) => {
|
|
460
|
+
return (
|
|
461
|
+
<button
|
|
462
|
+
className={`btn btn-${variant} btn-${size}`}
|
|
463
|
+
disabled={disabled}
|
|
464
|
+
onClick={onClick}
|
|
465
|
+
>
|
|
466
|
+
{children}
|
|
467
|
+
</button>
|
|
468
|
+
);
|
|
226
469
|
};
|
|
470
|
+
|
|
471
|
+
// Export mit displayName zum Debuggen
|
|
472
|
+
Button.displayName = 'Button';
|
|
227
473
|
```
|
|
228
474
|
|
|
229
|
-
###
|
|
475
|
+
### 2. React.memo für Performance
|
|
230
476
|
|
|
231
477
|
```typescript
|
|
232
|
-
|
|
233
|
-
export const useLocalStorage = <T>(
|
|
234
|
-
key: string,
|
|
235
|
-
initialValue: T
|
|
236
|
-
): [T, (value: T) => void] => {
|
|
237
|
-
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
238
|
-
try {
|
|
239
|
-
const item = window.localStorage.getItem(key);
|
|
240
|
-
return item ? JSON.parse(item) : initialValue;
|
|
241
|
-
} catch {
|
|
242
|
-
return initialValue;
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
const setValue = (value: T) => {
|
|
247
|
-
setStoredValue(value);
|
|
248
|
-
window.localStorage.setItem(key, JSON.stringify(value));
|
|
249
|
-
};
|
|
478
|
+
import { FC, memo } from 'react';
|
|
250
479
|
|
|
251
|
-
|
|
252
|
-
|
|
480
|
+
interface UserCardProps {
|
|
481
|
+
user: User;
|
|
482
|
+
onSelect: (userId: string) => void;
|
|
483
|
+
}
|
|
253
484
|
|
|
254
|
-
//
|
|
255
|
-
const
|
|
485
|
+
// Memoisierte Komponente
|
|
486
|
+
export const UserCard: FC<UserCardProps> = memo(({ user, onSelect }) => {
|
|
487
|
+
return (
|
|
488
|
+
<div onClick={() => onSelect(user.id)}>
|
|
489
|
+
<h3>{user.name}</h3>
|
|
490
|
+
<p>{user.email}</p>
|
|
491
|
+
</div>
|
|
492
|
+
);
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
UserCard.displayName = 'UserCard';
|
|
496
|
+
|
|
497
|
+
// Mit benutzerdefiniertem Vergleich
|
|
498
|
+
export const UserCardCustom: FC<UserCardProps> = memo(
|
|
499
|
+
({ user, onSelect }) => {
|
|
500
|
+
return (
|
|
501
|
+
<div onClick={() => onSelect(user.id)}>
|
|
502
|
+
<h3>{user.name}</h3>
|
|
503
|
+
</div>
|
|
504
|
+
);
|
|
505
|
+
},
|
|
506
|
+
(prevProps, nextProps) => {
|
|
507
|
+
// true zurückgeben, wenn Props gleich sind (kein Re-Render)
|
|
508
|
+
return prevProps.user.id === nextProps.user.id;
|
|
509
|
+
}
|
|
510
|
+
);
|
|
256
511
|
```
|
|
257
512
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
### Imports-Reihenfolge
|
|
513
|
+
### 3. forwardRef für Refs
|
|
261
514
|
|
|
262
515
|
```typescript
|
|
263
|
-
|
|
264
|
-
import { FC, useState, useEffect } from 'react';
|
|
516
|
+
import { forwardRef, InputHTMLAttributes } from 'react';
|
|
265
517
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
518
|
+
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
519
|
+
label?: string;
|
|
520
|
+
error?: string;
|
|
521
|
+
}
|
|
269
522
|
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
|
|
523
|
+
// Komponente mit forwardRef
|
|
524
|
+
export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
525
|
+
({ label, error, ...props }, ref) => {
|
|
526
|
+
return (
|
|
527
|
+
<div>
|
|
528
|
+
{label && <label>{label}</label>}
|
|
529
|
+
<input ref={ref} {...props} />
|
|
530
|
+
{error && <span>{error}</span>}
|
|
531
|
+
</div>
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
);
|
|
273
535
|
|
|
274
|
-
|
|
275
|
-
import { helper } from './utils';
|
|
536
|
+
Input.displayName = 'Input';
|
|
276
537
|
|
|
277
|
-
//
|
|
278
|
-
|
|
538
|
+
// Verwendung
|
|
539
|
+
const MyForm = () => {
|
|
540
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
279
541
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
542
|
+
const focusInput = () => {
|
|
543
|
+
inputRef.current?.focus();
|
|
544
|
+
};
|
|
283
545
|
|
|
284
|
-
|
|
546
|
+
return <Input ref={inputRef} label="Name" />;
|
|
547
|
+
};
|
|
548
|
+
```
|
|
285
549
|
|
|
286
|
-
|
|
287
|
-
// ✅ GUT - Named exports (bevorzugt)
|
|
288
|
-
export const Button: FC = () => { };
|
|
289
|
-
export const Input: FC = () => { };
|
|
550
|
+
## Dateistruktur von Komponenten
|
|
290
551
|
|
|
291
|
-
|
|
292
|
-
// components/atoms/index.ts
|
|
293
|
-
export { Button } from './Button';
|
|
294
|
-
export { Input } from './Input';
|
|
552
|
+
### Einfache Komponente
|
|
295
553
|
|
|
296
|
-
|
|
297
|
-
|
|
554
|
+
```
|
|
555
|
+
Button/
|
|
556
|
+
├── Button.tsx # Hauptkomponente
|
|
557
|
+
├── Button.test.tsx # Tests
|
|
558
|
+
├── Button.stories.tsx # Storybook
|
|
559
|
+
└── index.ts # Exporte
|
|
298
560
|
```
|
|
299
561
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
562
|
+
```typescript
|
|
563
|
+
// Button.tsx
|
|
564
|
+
import { FC, ButtonHTMLAttributes } from 'react';
|
|
565
|
+
import { cn } from '@/utils/classnames';
|
|
303
566
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
"semi": true,
|
|
307
|
-
"singleQuote": true,
|
|
308
|
-
"tabWidth": 2,
|
|
309
|
-
"useTabs": false,
|
|
310
|
-
"printWidth": 90,
|
|
311
|
-
"trailingComma": "none",
|
|
312
|
-
"arrowParens": "avoid"
|
|
567
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
568
|
+
variant?: 'primary' | 'secondary';
|
|
313
569
|
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### ESLint-Regeln
|
|
317
570
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
extends: [
|
|
321
|
-
'eslint:recommended',
|
|
322
|
-
'plugin:@typescript-eslint/recommended',
|
|
323
|
-
'plugin:react/recommended',
|
|
324
|
-
'plugin:react-hooks/recommended'
|
|
325
|
-
],
|
|
326
|
-
rules: {
|
|
327
|
-
'@typescript-eslint/no-explicit-any': 'error',
|
|
328
|
-
'@typescript-eslint/explicit-function-return-type': 'warn',
|
|
329
|
-
'react/prop-types': 'off',
|
|
330
|
-
'react-hooks/rules-of-hooks': 'error',
|
|
331
|
-
'react-hooks/exhaustive-deps': 'warn'
|
|
332
|
-
}
|
|
571
|
+
export const Button: FC<ButtonProps> = ({ variant = 'primary', ...props }) => {
|
|
572
|
+
return <button className={cn('btn', `btn-${variant}`)} {...props} />;
|
|
333
573
|
};
|
|
334
574
|
```
|
|
335
575
|
|
|
336
|
-
|
|
576
|
+
```typescript
|
|
577
|
+
// index.ts
|
|
578
|
+
export { Button } from './Button';
|
|
579
|
+
export type { ButtonProps } from './Button';
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
## JSDoc/TSDoc-Dokumentation
|
|
337
583
|
|
|
338
|
-
###
|
|
584
|
+
### Komponenten dokumentieren
|
|
339
585
|
|
|
340
586
|
```typescript
|
|
341
587
|
/**
|
|
342
|
-
*
|
|
588
|
+
* Benutzerdefinierter Button mit verschiedenen visuellen Varianten.
|
|
343
589
|
*
|
|
344
|
-
* @
|
|
345
|
-
*
|
|
590
|
+
* @remarks
|
|
591
|
+
* Diese Komponente erweitert die nativen HTMLButtonElement-Props,
|
|
592
|
+
* sodass alle Standard-HTML-Attribute verwendet werden können.
|
|
346
593
|
*
|
|
347
594
|
* @example
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
595
|
+
* ```tsx
|
|
596
|
+
* // Primärer Button
|
|
597
|
+
* <Button variant="primary" onClick={handleClick}>
|
|
598
|
+
* Klick mich
|
|
599
|
+
* </Button>
|
|
600
|
+
*
|
|
601
|
+
* // Deaktivierter Button
|
|
602
|
+
* <Button variant="secondary" disabled>
|
|
603
|
+
* Deaktiviert
|
|
604
|
+
* </Button>
|
|
605
|
+
* ```
|
|
352
606
|
*/
|
|
353
|
-
export const
|
|
354
|
-
|
|
355
|
-
let age = today.getFullYear() - birthDate.getFullYear();
|
|
356
|
-
const monthDiff = today.getMonth() - birthDate.getMonth();
|
|
357
|
-
|
|
358
|
-
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
|
359
|
-
age--;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return age;
|
|
607
|
+
export const Button: FC<ButtonProps> = ({ variant, children, ...rest }) => {
|
|
608
|
+
return <button className={`btn-${variant}`} {...rest}>{children}</button>;
|
|
363
609
|
};
|
|
364
610
|
```
|
|
365
611
|
|
|
366
|
-
|
|
612
|
+
## Allgemeine bewährte Praktiken
|
|
367
613
|
|
|
368
|
-
|
|
369
|
-
// ✅ GUT - Erklärt das "Warum"
|
|
370
|
-
// Verwende requestAnimationFrame um Layout-Thrashing zu vermeiden
|
|
371
|
-
const optimizedScroll = () => {
|
|
372
|
-
requestAnimationFrame(() => {
|
|
373
|
-
updateScrollPosition();
|
|
374
|
-
});
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
// ❌ SCHLECHT - Erklärt das "Was" (offensichtlich)
|
|
378
|
-
// Inkrementiere den Zähler um 1
|
|
379
|
-
count++;
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
## Best Practices
|
|
383
|
-
|
|
384
|
-
### 1. Komponenten klein halten
|
|
614
|
+
### 1. Eine Komponente = Eine Datei
|
|
385
615
|
|
|
386
616
|
```typescript
|
|
387
|
-
//
|
|
388
|
-
export const
|
|
389
|
-
|
|
390
|
-
);
|
|
617
|
+
// ❌ Schlecht – Mehrere Komponenten in einer Datei
|
|
618
|
+
export const Button = () => {};
|
|
619
|
+
export const Input = () => {};
|
|
620
|
+
export const Form = () => {};
|
|
391
621
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
<p>{user.email}</p>
|
|
396
|
-
</div>
|
|
397
|
-
);
|
|
622
|
+
// ✅ Gut – Eine Komponente pro Datei
|
|
623
|
+
// Button.tsx
|
|
624
|
+
export const Button = () => {};
|
|
398
625
|
|
|
399
|
-
//
|
|
400
|
-
export const
|
|
401
|
-
<div>
|
|
402
|
-
<img src={user.avatar} alt={user.name} />
|
|
403
|
-
<h3>{user.name}</h3>
|
|
404
|
-
<p>{user.email}</p>
|
|
405
|
-
{/* Noch 100 weitere Zeilen... */}
|
|
406
|
-
</div>
|
|
407
|
-
);
|
|
626
|
+
// Input.tsx
|
|
627
|
+
export const Input = () => {};
|
|
408
628
|
```
|
|
409
629
|
|
|
410
|
-
### 2.
|
|
630
|
+
### 2. Any vermeiden
|
|
411
631
|
|
|
412
632
|
```typescript
|
|
413
|
-
//
|
|
414
|
-
|
|
415
|
-
|
|
633
|
+
// ❌ Schlecht
|
|
634
|
+
const handleData = (data: any) => {
|
|
635
|
+
console.log(data.name);
|
|
636
|
+
};
|
|
416
637
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
638
|
+
// ✅ Gut
|
|
639
|
+
interface Data {
|
|
640
|
+
name: string;
|
|
641
|
+
}
|
|
420
642
|
|
|
421
|
-
|
|
643
|
+
const handleData = (data: Data) => {
|
|
644
|
+
console.log(data.name);
|
|
422
645
|
};
|
|
423
646
|
|
|
424
|
-
//
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
return (
|
|
429
|
-
<div>
|
|
430
|
-
{isLoading ? (
|
|
431
|
-
<Spinner />
|
|
432
|
-
) : error ? (
|
|
433
|
-
<ErrorMessage error={error} />
|
|
434
|
-
) : user ? (
|
|
435
|
-
<div>{user.name}</div>
|
|
436
|
-
) : (
|
|
437
|
-
<NotFound />
|
|
438
|
-
)}
|
|
439
|
-
</div>
|
|
440
|
-
);
|
|
647
|
+
// ✅ Gut – Falls wirklich nötig, dokumentieren
|
|
648
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
649
|
+
const handleUnknown = (data: any) => {
|
|
650
|
+
// Grund für die Verwendung von any...
|
|
441
651
|
};
|
|
442
652
|
```
|
|
443
653
|
|
|
444
|
-
### 3.
|
|
654
|
+
### 3. Benannte Exporte vs. Default
|
|
445
655
|
|
|
446
656
|
```typescript
|
|
447
|
-
// ✅
|
|
448
|
-
export const Button
|
|
449
|
-
|
|
450
|
-
};
|
|
657
|
+
// ✅ Benannte Exporte bevorzugen
|
|
658
|
+
export const Button = () => {};
|
|
659
|
+
export const Input = () => {};
|
|
451
660
|
|
|
452
|
-
// ❌
|
|
453
|
-
export
|
|
454
|
-
return (
|
|
455
|
-
<button className={\`btn-\${props.variant} btn-\${props.size}\`}>
|
|
456
|
-
{props.children}
|
|
457
|
-
</button>
|
|
458
|
-
);
|
|
459
|
-
};
|
|
661
|
+
// ❌ Default-Exporte vermeiden (außer bei Seiten/Routen)
|
|
662
|
+
export default Button;
|
|
460
663
|
```
|
|
461
664
|
|
|
462
|
-
|
|
665
|
+
### 4. Gruppierte und geordnete Imports
|
|
463
666
|
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
- [ ] TypeScript strict mode aktiviert
|
|
469
|
-
- [ ] Keine `any`-Types
|
|
667
|
+
```typescript
|
|
668
|
+
// 1. React und externe Bibliotheken
|
|
669
|
+
import { FC, useState, useEffect } from 'react';
|
|
670
|
+
import { useQuery } from '@tanstack/react-query';
|
|
470
671
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
-
|
|
486
|
-
|
|
487
|
-
|
|
672
|
+
// 2. Absolute interne Imports
|
|
673
|
+
import { Button } from '@/components/atoms/Button';
|
|
674
|
+
import { useAuth } from '@/hooks/useAuth';
|
|
675
|
+
|
|
676
|
+
// 3. Relative Imports
|
|
677
|
+
import { UserCard } from './UserCard';
|
|
678
|
+
|
|
679
|
+
// 4. Typen
|
|
680
|
+
import type { User } from '@/types/user.types';
|
|
681
|
+
|
|
682
|
+
// 5. Stile und Assets
|
|
683
|
+
import './styles.css';
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
## NPM-Skripte
|
|
687
|
+
|
|
688
|
+
```json
|
|
689
|
+
{
|
|
690
|
+
"scripts": {
|
|
691
|
+
"dev": "vite",
|
|
692
|
+
"build": "tsc && vite build",
|
|
693
|
+
"preview": "vite preview",
|
|
694
|
+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
|
695
|
+
"lint:fix": "eslint . --ext ts,tsx --fix",
|
|
696
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,json,css,md}\"",
|
|
697
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,css,md}\"",
|
|
698
|
+
"type-check": "tsc --noEmit",
|
|
699
|
+
"test": "vitest",
|
|
700
|
+
"test:ui": "vitest --ui",
|
|
701
|
+
"test:coverage": "vitest --coverage"
|
|
702
|
+
}
|
|
703
|
+
}
|
|
488
704
|
```
|
|
489
705
|
|
|
490
706
|
## Fazit
|
|
491
707
|
|
|
492
|
-
|
|
708
|
+
Coding Standards gewährleisten:
|
|
493
709
|
|
|
494
|
-
1. ✅
|
|
495
|
-
2. ✅
|
|
496
|
-
3. ✅
|
|
497
|
-
4. ✅
|
|
498
|
-
5. ✅
|
|
710
|
+
1. ✅ Code-Konsistenz im gesamten Team
|
|
711
|
+
2. ✅ Bessere Wartbarkeit
|
|
712
|
+
3. ✅ Weniger Fehler
|
|
713
|
+
4. ✅ Einfachere Code-Reviews
|
|
714
|
+
5. ✅ Schnelleres Onboarding für neue Entwickler
|
|
499
715
|
|
|
500
|
-
**Goldene Regel**: Code
|
|
716
|
+
**Goldene Regel**: Code sollte so geschrieben werden, dass er von Menschen gelesen werden kann – nicht nur von Maschinen ausgeführt.
|