create-win-project 1.4.0 → 2.0.0
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/LICENSE +1 -1
- package/README.md +54 -147
- package/checks/check-compatibility.js +37 -8
- package/checks/check-generated-project.js +27 -3
- package/checks/check-library.js +13 -3
- package/checks/check-package.js +15 -0
- package/checks/classify-changes.js +5 -15
- package/checks/run-compatibility-shard.js +21 -0
- package/docs/README.md +20 -0
- package/docs/capabilities.md +13 -0
- package/docs/compatibility.md +13 -0
- package/docs/generated-project.md +12 -0
- package/docs/getting-started.md +26 -0
- package/docs/{ARCHITECTURE.md → maintainers/architecture.md} +3 -3
- package/docs/maintainers/ci-strategy.md +46 -0
- package/docs/{CONTRIBUTING.md → maintainers/contributing.md} +7 -7
- package/docs/migration-v2.md +13 -0
- package/docs/production-contract.md +24 -0
- package/library/INDEX.md +1 -1
- package/library/compatibility-impact.json +14 -0
- package/library/development-tools/devops/makefile/commands.md +11 -0
- package/library/development-tools/devops/makefile/definition.json +2 -2
- package/library/development-tools/devops/makefile/docker.md +9 -0
- package/library/development-tools/devops/makefile/validation.md +5 -0
- package/library/features/sqlalchemy-alembic.md +17 -0
- package/library/optional-features/concerns/zod/errors.md +5 -0
- package/library/optional-features/concerns/zod/testing.md +5 -0
- package/library/optional-features/concerns/zod/validation.md +21 -0
- package/library/optional-features/styling/css-modules/definition.json +3 -2
- package/library/optional-features/styling/css-modules/responsive.md +5 -0
- package/library/optional-features/styling/css-modules/theme.md +7 -0
- package/library/stacks/expo/definition.json +2 -2
- package/library/stacks/fastapi/architecture.md +40 -0
- package/library/stacks/fastapi/definition.json +39 -0
- package/library/stacks/fastapi/runtime.md +25 -0
- package/library/stacks/fastapi/security.md +26 -0
- package/library/stacks/fastapi/structure.md +27 -0
- package/library/stacks/fastapi/testing.md +23 -0
- package/library/stacks/nextjs/definition.json +2 -2
- package/library/stacks/no-frontend/definition.json +1 -1
- package/library/stacks/react-vite/definition.json +2 -2
- package/library/tested-versions.json +42 -2
- package/library/universal/coding-rules/definition.json +3 -3
- package/library/universal/coding-rules/hygiene.md +9 -0
- package/library/universal/coding-rules/naming.md +17 -0
- package/library/universal/git-conventions/branches.md +5 -0
- package/library/universal/git-conventions/commits.md +7 -0
- package/library/universal/git-conventions/definition.json +4 -2
- package/library/universal/git-conventions/workflow.md +5 -0
- package/library/universal/typescript/boundaries.md +13 -0
- package/library/universal/typescript/definition.json +3 -3
- package/library/universal/typescript/errors.md +5 -0
- package/library/universal/typescript/patterns.md +7 -0
- package/package.json +4 -6
- package/src/cli/arguments.js +11 -0
- package/src/cli/main.js +18 -0
- package/src/cli/questions.js +16 -15
- package/src/cli/system-check.js +22 -2
- package/src/engine/load-library.js +3 -2
- package/src/engine/project-files.js +10 -1
- package/src/engine/project-guidance.js +2 -1
- package/src/engine/project-shapes.js +4 -4
- package/src/engine/render-templates.js +3 -0
- package/src/engine/tested-versions.js +21 -2
- package/src/engine/upgrade-report.js +20 -0
- package/src/stacks/available-stacks.js +2 -0
- package/src/stacks/backends/fastapi/ci.js +3 -0
- package/src/stacks/backends/fastapi/create-files.js +874 -0
- package/src/stacks/backends/fastapi/docker.js +75 -0
- package/src/stacks/backends/fastapi/environment.js +3 -0
- package/src/stacks/backends/fastapi/index.js +32 -0
- package/src/stacks/compose-files.js +19 -1
- package/src/stacks/create-project.js +128 -7
- package/src/stacks/frontends/nextjs/index.js +1 -1
- package/src/stacks/frontends/react-native/create-files.js +4 -1
- package/src/stacks/frontends/react-native/environment.js +1 -1
- package/src/stacks/frontends/react-native/index.js +1 -1
- package/src/stacks/frontends/react-vite/environment.js +1 -1
- package/src/stacks/frontends/react-vite/index.js +1 -1
- package/src/stacks/shared/capability-packs.js +31 -0
- package/src/stacks/shared/environment.js +12 -4
- package/src/stacks/shared/javascript-package.js +6 -0
- package/templates/ci/fastapi.yml +62 -0
- package/templates/docker/compose-prod/fastapi.yml +52 -0
- package/templates/docker/compose-prod/springboot.yml +19 -1
- package/templates/docker/dockerfile/fastapi.dev.dockerfile +9 -0
- package/templates/docker/dockerfile/fastapi.prod.dockerfile +11 -0
- package/templates/docker/dockerfile/nextjs.prod.dockerfile +1 -0
- package/templates/docker/dockerfile/springboot.prod.dockerfile +4 -1
- package/templates/docker/dockerfile/vite.prod.dockerfile +2 -1
- package/templates/makefile/fastapi.mk +97 -0
- package/library/development-tools/devops/makefile/makefile.md +0 -556
- package/library/optional-features/concerns/zod.md +0 -174
- package/library/optional-features/styling/css-modules/css-modules-extensions.md +0 -267
- package/library/universal/coding-rules/coding-rules.md +0 -281
- package/library/universal/git-conventions/git-conventions.md +0 -186
- package/library/universal/typescript/typescript.md +0 -272
- /package/docs/{CONTENT_MODEL.md → maintainers/content-model.md} +0 -0
- /package/docs/{DEPENDENCY_MAINTENANCE.md → maintainers/dependencies.md} +0 -0
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
# Git Conventions (Universal)
|
|
2
|
-
|
|
3
|
-
Applies to every project regardless of stack.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Branch Structure
|
|
8
|
-
| Branch | Purpose |
|
|
9
|
-
|--------------|-----------------------------------------------|
|
|
10
|
-
| `main` | Production — always stable, always deployable |
|
|
11
|
-
| `dev` | Integration — all features merge here first |
|
|
12
|
-
| `feature/*` | New capability |
|
|
13
|
-
| `fix/*` | Bug fix |
|
|
14
|
-
| `refactor/*` | Restructure without behavior change |
|
|
15
|
-
| `chore/*` | Dependencies, config, tooling |
|
|
16
|
-
| `docs/*` | Documentation only |
|
|
17
|
-
| `test/*` | Adding or updating tests only |
|
|
18
|
-
|
|
19
|
-
## Branch Rules
|
|
20
|
-
- NEVER commit directly to `main` or `dev`
|
|
21
|
-
- ALWAYS branch off `dev` — never off `main`
|
|
22
|
-
- NEVER merge or create PRs unless explicitly asked
|
|
23
|
-
- NEVER push to remote unless explicitly asked
|
|
24
|
-
- One logical change per branch — keep branches small and focused
|
|
25
|
-
|
|
26
|
-
## Starting a Branch
|
|
27
|
-
```bash
|
|
28
|
-
git checkout dev
|
|
29
|
-
git pull origin dev
|
|
30
|
-
git checkout -b <type>/<short-description>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Examples
|
|
34
|
-
```bash
|
|
35
|
-
git checkout -b feature/user-profile-page
|
|
36
|
-
git checkout -b fix/token-expiry-race
|
|
37
|
-
git checkout -b refactor/auth-feature-module
|
|
38
|
-
git checkout -b chore/update-dependencies
|
|
39
|
-
git checkout -b docs/update-api-endpoints
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Commit Convention
|
|
45
|
-
|
|
46
|
-
### Format
|
|
47
|
-
```
|
|
48
|
-
type(scope): short description
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Rules
|
|
52
|
-
- Lowercase only — no uppercase anywhere
|
|
53
|
-
- No period at the end
|
|
54
|
-
- Present tense — "add" not "added", "fix" not "fixed"
|
|
55
|
-
- Under 72 characters
|
|
56
|
-
- One logical change per commit
|
|
57
|
-
|
|
58
|
-
### Types
|
|
59
|
-
| Type | When to use |
|
|
60
|
-
|------------|---------------------------------------------------|
|
|
61
|
-
| `feat` | New feature or capability |
|
|
62
|
-
| `fix` | Bug fix |
|
|
63
|
-
| `refactor` | Restructure without behavior change |
|
|
64
|
-
| `chore` | Deps, config, tooling — no production code change |
|
|
65
|
-
| `docs` | Documentation only |
|
|
66
|
-
| `test` | Adding or updating tests |
|
|
67
|
-
| `ci` | GitHub Actions or CI/CD workflow changes |
|
|
68
|
-
| `style` | Formatting, whitespace — no logic change |
|
|
69
|
-
|
|
70
|
-
### Scopes (React + Spring Boot)
|
|
71
|
-
| Scope | When to use |
|
|
72
|
-
|------------|------------------------------------|
|
|
73
|
-
| `frontend` | Anything inside /frontend |
|
|
74
|
-
| `backend` | Anything inside /backend |
|
|
75
|
-
| `docker` | Dockerfile or docker-compose |
|
|
76
|
-
| `ci` | GitHub Actions workflows |
|
|
77
|
-
| `docs` | Anything inside /docs |
|
|
78
|
-
| `deps` | Dependency updates (either side) |
|
|
79
|
-
|
|
80
|
-
### Scopes (Next.js projects)
|
|
81
|
-
| Scope | When to use |
|
|
82
|
-
|------------|------------------------------------|
|
|
83
|
-
| `app` | Next.js app router, pages, layouts |
|
|
84
|
-
| `api` | API routes or server actions |
|
|
85
|
-
| `db` | Database schema, migrations |
|
|
86
|
-
| `auth` | Authentication logic |
|
|
87
|
-
| `ci` | GitHub Actions workflows |
|
|
88
|
-
| `docs` | Anything inside /docs |
|
|
89
|
-
| `deps` | Dependency updates |
|
|
90
|
-
|
|
91
|
-
### Examples
|
|
92
|
-
```bash
|
|
93
|
-
feat(frontend): add user profile page
|
|
94
|
-
feat(backend): add paper download endpoint
|
|
95
|
-
fix(backend): resolve token expiry race condition
|
|
96
|
-
fix(frontend): correct redirect after logout
|
|
97
|
-
refactor(backend): move auth logic into feature module
|
|
98
|
-
refactor(frontend): restructure features folder
|
|
99
|
-
chore(deps): update spring boot to 3.5.1
|
|
100
|
-
chore(docker): add maven cache volume
|
|
101
|
-
docs(api): update error contract with traceId field
|
|
102
|
-
test(backend): add unit tests for auth service
|
|
103
|
-
test(frontend): add vitest tests for useAuth hook
|
|
104
|
-
ci(backend): add postgresql service to ci workflow
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## Daily Workflow
|
|
110
|
-
```bash
|
|
111
|
-
# 1. Always start from updated dev
|
|
112
|
-
git checkout dev
|
|
113
|
-
git pull origin dev
|
|
114
|
-
|
|
115
|
-
# 2. Create your branch
|
|
116
|
-
git checkout -b <type>/<description>
|
|
117
|
-
|
|
118
|
-
# 3. Work in small, logical commits
|
|
119
|
-
git add .
|
|
120
|
-
git commit -m "type(scope): description"
|
|
121
|
-
|
|
122
|
-
# 4. Push your branch
|
|
123
|
-
git push origin <branch-name>
|
|
124
|
-
|
|
125
|
-
# 5. Open PR → dev (only when explicitly asked)
|
|
126
|
-
# 6. Merge dev → main (only when explicitly asked)
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## .gitignore — Always Include
|
|
132
|
-
```
|
|
133
|
-
# Environment
|
|
134
|
-
.env
|
|
135
|
-
.env.local
|
|
136
|
-
.env.production
|
|
137
|
-
|
|
138
|
-
# Dependencies
|
|
139
|
-
node_modules/
|
|
140
|
-
.mvn/
|
|
141
|
-
|
|
142
|
-
# Build outputs
|
|
143
|
-
dist/
|
|
144
|
-
build/
|
|
145
|
-
target/
|
|
146
|
-
.next/
|
|
147
|
-
|
|
148
|
-
# IDE
|
|
149
|
-
.idea/
|
|
150
|
-
.vscode/
|
|
151
|
-
*.iml
|
|
152
|
-
|
|
153
|
-
# OS
|
|
154
|
-
.DS_Store
|
|
155
|
-
Thumbs.db
|
|
156
|
-
|
|
157
|
-
# Logs
|
|
158
|
-
*.log
|
|
159
|
-
logs/
|
|
160
|
-
|
|
161
|
-
# Docker volumes (if local)
|
|
162
|
-
postgres-data/
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## Agent Rules
|
|
168
|
-
```
|
|
169
|
-
Never:
|
|
170
|
-
→ commit directly to main or dev
|
|
171
|
-
→ branch off main
|
|
172
|
-
→ push or create PRs unless explicitly asked
|
|
173
|
-
→ put multiple logical changes in one commit
|
|
174
|
-
→ use vague commit messages ("fix stuff", "update code")
|
|
175
|
-
|
|
176
|
-
Always:
|
|
177
|
-
→ branch off dev
|
|
178
|
-
→ one logical change per commit
|
|
179
|
-
→ follow type(scope): description format
|
|
180
|
-
→ present tense in commit messages
|
|
181
|
-
|
|
182
|
-
When asked to commit:
|
|
183
|
-
→ Stage only files relevant to the current task
|
|
184
|
-
→ Write a precise commit message following the convention
|
|
185
|
-
→ Do not push unless explicitly asked
|
|
186
|
-
```
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
# TypeScript Rules (Universal)
|
|
2
|
-
|
|
3
|
-
Applies to every TypeScript project.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Strict Mode — Always On
|
|
8
|
-
```json
|
|
9
|
-
// tsconfig.json
|
|
10
|
-
{
|
|
11
|
-
"compilerOptions": {
|
|
12
|
-
"strict": true,
|
|
13
|
-
"noUncheckedIndexedAccess": true,
|
|
14
|
-
"noImplicitReturns": true,
|
|
15
|
-
"noFallthroughCasesInSwitch": true,
|
|
16
|
-
"exactOptionalPropertyTypes": true
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
These flags catch real bugs. Never disable them.
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## No `any`
|
|
26
|
-
- Never use `any` unless absolutely unavoidable
|
|
27
|
-
- When unavoidable: add `// reason:` comment explaining why
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
// ❌
|
|
31
|
-
const data: any = fetchUser()
|
|
32
|
-
function process(input: any) { ... }
|
|
33
|
-
|
|
34
|
-
// ✅
|
|
35
|
-
const data: unknown = fetchUser()
|
|
36
|
-
function process(input: UserInput) { ... }
|
|
37
|
-
|
|
38
|
-
// ✅ justified any with comment
|
|
39
|
-
// reason: third-party library has no types and @types package doesn't exist
|
|
40
|
-
const chart = new (window as any).ChartLib()
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Alternatives to `any`
|
|
44
|
-
| Instead of `any` | Use |
|
|
45
|
-
|------------------|-------------------------|
|
|
46
|
-
| Unknown data | `unknown` |
|
|
47
|
-
| Flexible object | `Record<string, unknown>` |
|
|
48
|
-
| Multiple types | Union `string \| number` |
|
|
49
|
-
| Optional | `T \| undefined` |
|
|
50
|
-
| Nullable | `T \| null` |
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Type vs Interface
|
|
55
|
-
```typescript
|
|
56
|
-
// Interface — for objects that may be extended or implemented
|
|
57
|
-
interface User {
|
|
58
|
-
id: string
|
|
59
|
-
name: string
|
|
60
|
-
email: string
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Type — for unions, intersections, primitives, tuples
|
|
64
|
-
type UserId = string
|
|
65
|
-
type UserRole = 'ADMIN' | 'USER' | 'MODERATOR'
|
|
66
|
-
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
|
|
67
|
-
type UserWithRole = User & { role: UserRole }
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Rule
|
|
71
|
-
- Objects → `interface` (extends naturally, better error messages)
|
|
72
|
-
- Everything else → `type`
|
|
73
|
-
- Never use `I` prefix for interfaces (`IUser` → `User`)
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Discriminated Unions for State
|
|
78
|
-
```typescript
|
|
79
|
-
// ❌ scattered boolean flags
|
|
80
|
-
type State = {
|
|
81
|
-
isLoading: boolean
|
|
82
|
-
isError: boolean
|
|
83
|
-
isSuccess: boolean
|
|
84
|
-
data?: User
|
|
85
|
-
error?: Error
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// ✅ discriminated union — mutually exclusive states
|
|
89
|
-
type State =
|
|
90
|
-
| { status: 'idle' }
|
|
91
|
-
| { status: 'loading' }
|
|
92
|
-
| { status: 'success'; data: User }
|
|
93
|
-
| { status: 'error'; error: Error }
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## Unknown Over Any for Errors
|
|
99
|
-
```typescript
|
|
100
|
-
// ❌
|
|
101
|
-
} catch (error: any) {
|
|
102
|
-
console.log(error.message)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ✅
|
|
106
|
-
} catch (error: unknown) {
|
|
107
|
-
const message = error instanceof Error ? error.message : 'Unknown error'
|
|
108
|
-
logger.error(message)
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## Generics
|
|
115
|
-
Use when genuinely reusable — not for ceremony.
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
// ✅ genuinely reusable
|
|
119
|
-
function first<T>(array: T[]): T | undefined {
|
|
120
|
-
return array[0]
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ✅ reusable operation result inside the application
|
|
124
|
-
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
|
|
125
|
-
|
|
126
|
-
// ❌ unnecessary generic
|
|
127
|
-
function getUserName<T extends User>(user: T): string {
|
|
128
|
-
return user.name
|
|
129
|
-
// just use: function getUserName(user: User): string
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## Zod for Runtime Validation
|
|
136
|
-
|
|
137
|
-
Use Zod for runtime validation **when** this project has runtime validation needs (form input, API responses, external data). If the project has no such need, this section does not apply — the rules are optional.
|
|
138
|
-
|
|
139
|
-
TypeScript types are compile-time only. Use Zod at runtime boundaries.
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
// Define schema
|
|
143
|
-
const UserSchema = z.object({
|
|
144
|
-
id: z.string().uuid(),
|
|
145
|
-
name: z.string().min(1),
|
|
146
|
-
email: z.string().email(),
|
|
147
|
-
role: z.enum(['ADMIN', 'USER']),
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
// Infer type from schema — single source of truth
|
|
151
|
-
type User = z.infer<typeof UserSchema>
|
|
152
|
-
|
|
153
|
-
// Validate at runtime
|
|
154
|
-
const user = UserSchema.parse(apiResponse.data)
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### When to use Zod
|
|
158
|
-
- Form validation (via React Hook Form resolver)
|
|
159
|
-
- API response parsing
|
|
160
|
-
- Environment variable validation (t3-env)
|
|
161
|
-
- Any external data entering the system
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## Where Types Live
|
|
166
|
-
|
|
167
|
-
### Decision tree
|
|
168
|
-
```
|
|
169
|
-
Is this type used across multiple features?
|
|
170
|
-
→ src/types/[name].ts
|
|
171
|
-
|
|
172
|
-
Is this type specific to one feature?
|
|
173
|
-
→ src/features/[name]/types/index.ts
|
|
174
|
-
|
|
175
|
-
Is this type a Zod schema + inferred type?
|
|
176
|
-
→ src/features/[name]/schemas/[name].schema.ts
|
|
177
|
-
|
|
178
|
-
Is this type shared by several transport clients?
|
|
179
|
-
→ src/types/transport.ts
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### Global types (src/types/)
|
|
183
|
-
```typescript
|
|
184
|
-
// src/types/transport.ts
|
|
185
|
-
// Successful endpoints return their normal DTO. Model only genuinely shared shapes.
|
|
186
|
-
export type ProblemDetails = { type: string; title: string; status: number; detail?: string; traceId?: string }
|
|
187
|
-
|
|
188
|
-
// src/types/pagination.ts
|
|
189
|
-
export type PaginatedResponse<T> = {
|
|
190
|
-
data: T[]
|
|
191
|
-
total: number
|
|
192
|
-
page: number
|
|
193
|
-
limit: number
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
---
|
|
198
|
-
|
|
199
|
-
## Type Assertions
|
|
200
|
-
Avoid `as` unless justified.
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
// ❌ lying to TypeScript
|
|
204
|
-
const user = data as User
|
|
205
|
-
|
|
206
|
-
// ✅ validate first, then trust
|
|
207
|
-
const user = UserSchema.parse(data)
|
|
208
|
-
|
|
209
|
-
// ✅ justified assertion with comment
|
|
210
|
-
// reason: DOM ref is always set before this handler fires
|
|
211
|
-
const input = inputRef.current as HTMLInputElement
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## Enums vs Union Types
|
|
217
|
-
Prefer union types over enums for most cases.
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
// ❌ enum (compiles to weird JS, harder to iterate)
|
|
221
|
-
enum UserRole {
|
|
222
|
-
ADMIN = 'ADMIN',
|
|
223
|
-
USER = 'USER',
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// ✅ const object + union type (tree-shakeable, readable compiled output)
|
|
227
|
-
export const ROLES = {
|
|
228
|
-
ADMIN: 'ADMIN',
|
|
229
|
-
USER: 'USER',
|
|
230
|
-
} as const
|
|
231
|
-
|
|
232
|
-
export type UserRole = typeof ROLES[keyof typeof ROLES]
|
|
233
|
-
// → 'ADMIN' | 'USER'
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## Null vs Undefined
|
|
239
|
-
```typescript
|
|
240
|
-
// Use null: explicitly absent (API returns null, user cleared a field)
|
|
241
|
-
type User = { avatar: string | null }
|
|
242
|
-
|
|
243
|
-
// Use undefined: optionally present (optional function param, optional object key)
|
|
244
|
-
type Options = { timeout?: number }
|
|
245
|
-
|
|
246
|
-
// Never mix without reason — pick one for each case and be consistent
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
## Agent Rules
|
|
252
|
-
```
|
|
253
|
-
strict: true — never disable, never add ts-ignore without // reason:
|
|
254
|
-
|
|
255
|
-
Type a new variable?
|
|
256
|
-
→ Use the most specific type possible
|
|
257
|
-
→ Infer from Zod schema if validating external data
|
|
258
|
-
→ Use unknown for error catch blocks
|
|
259
|
-
|
|
260
|
-
New shared type?
|
|
261
|
-
→ If used in 2+ features → src/types/
|
|
262
|
-
→ If feature-specific → features/[name]/types/
|
|
263
|
-
|
|
264
|
-
New form?
|
|
265
|
-
→ Zod schema first → infer type → pass to React Hook Form
|
|
266
|
-
|
|
267
|
-
Avoid:
|
|
268
|
-
→ any (use unknown)
|
|
269
|
-
→ type assertions without reason comment
|
|
270
|
-
→ enums (use const object + union type)
|
|
271
|
-
→ I prefix on interfaces
|
|
272
|
-
```
|
|
File without changes
|
|
File without changes
|