Skip to content

Remove useDefineForClassFields from tsconfig#598

Merged
uldisrudzitis merged 1 commit intomasterfrom
fix-ts-useDefineForClassFields
Oct 29, 2025
Merged

Remove useDefineForClassFields from tsconfig#598
uldisrudzitis merged 1 commit intomasterfrom
fix-ts-useDefineForClassFields

Conversation

@uldisrudzitis
Copy link
Copy Markdown
Collaborator

@uldisrudzitis uldisrudzitis commented Oct 29, 2025

  • Remove useDefineForClassFields from tsconfig, use the default true value.
  • Remove deprecated @Select decorator.

Summary by CodeRabbit

  • Refactor
    • Refactored state management architecture for improved maintainability and consistency across components.
    • Made configuration properties readonly to enhance immutability guarantees.
    • Exported internal type definitions to improve type safety and reusability.
    • Added explicit type annotations for enhanced code clarity and reliability.
    • Simplified TypeScript configuration settings.

@uldisrudzitis uldisrudzitis self-assigned this Oct 29, 2025
@uldisrudzitis uldisrudzitis added Enhancement dependencies Pull requests that update a dependency file labels Oct 29, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 29, 2025

Walkthrough

This pull request systematically replaces NGXS @select decorators with explicit store.select() assignments in constructors across multiple components and services. Additionally, several properties are made readonly, type exports are added to a regional-costs state file, and a TypeScript compiler option is removed.

Changes

Cohort / File(s) Summary
App and Header Components
editor/src/app/app.component.ts, editor/src/app/header/header.component.ts, editor/src/app/header/preview-toggle.component.ts, editor/src/app/profile-dropdown/profile-dropdown.component.ts
Removed @select decorators from public observable properties (user$, showOverlay$, inputFocus$, isLoggedIn$, isSetup$, lastRoute$) and initialize them via explicit store.select() calls in constructors. Made configuration properties (title, sidebarFullscreenRoutes, sidebarFullWidthRoutes) readonly.
Shop Components
editor/src/app/shop/orders/shop-orders.component.ts, editor/src/app/shop/regional-costs/shop-regional-costs.component.ts
Replaced @Select-decorated observables (orders$, currency$, regionalCosts$) with explicit assignments in constructors using store.select().
Shop State File
editor/src/app/shop/regional-costs/shop-regional-costs.state.ts
Exported three previously internal interfaces: ShopRegion, ShopRegionalCost, and ShopRegionalCostsModel.
Media and Gallery Components
editor/src/app/sites/media/entry-gallery-editor.component.ts, editor/src/app/sites/media/entry-gallery-image-editor.component.ts, editor/src/app/sites/media/site-media.component.ts, editor/src/app/sites/sections/background-gallery-editor.component.ts
Removed @select decorators from currentSite$ observable; now initialized in constructor via store.select(). Made currentSite$ readonly or private readonly. Added explicit type annotations for boolean fields.
Settings and Auth
editor/src/app/sites/settings/site-settings.component.ts, editor/src/app/user/auth-guard.service.ts
Replaced @Select-decorated observables (user$, appState$, isLoggedIn$) with explicit readonly properties initialized in constructors using store.select().
TypeScript Configuration
editor/tsconfig.json
Removed the useDefineForClassFields: false compiler option.

Sequence Diagram

sequenceDiagram
    participant Component
    participant Constructor
    participant Store

    rect rgb(200, 220, 255)
    Note over Component,Store: Before: @Select Decorator Pattern
    Component->>Component: @Select(State) observable$
    Note over Component: Observable initialized via<br/>decorator metadata at class load
    end

    rect rgb(220, 240, 220)
    Note over Component,Store: After: Explicit Constructor Pattern
    Component->>Constructor: Component instantiation
    Constructor->>Store: store.select(State)
    Store-->>Constructor: Observable stream
    Constructor->>Component: this.observable$ = result
    Note over Component: Observable explicitly<br/>assigned in constructor
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Homogeneous pattern: The same decorator-to-constructor refactoring is consistently applied across 12 files, reducing per-file cognitive load.
  • Straightforward logic: No complex state transformations or business logic changes; purely initialization pattern shifts.
  • Minimal risk: Visibility changes (readonly, private) and type annotations are intentional and well-scoped.

Areas requiring attention during review:

  • Verify all store.select() selectors match their original @select decorators exactly (selector functions and state paths).
  • Confirm that private/readonly visibility changes on observables (e.g., currentSite$ in media components) don't break template bindings or external access.
  • Validate that the tsconfig.json change removing useDefineForClassFields: false aligns with the project's TypeScript target and doesn't introduce field initialization issues.
  • Check that private field initialization in constructors doesn't conflict with dependency injection ordering in any component.

Possibly related PRs

Poem

🐰 Decorators fade, constructors now take the lead,
Store selects bloom where seeds of @select recede,
Readonly fields stand firm, TypeScript options freed,
Each observable explicit, tending every need.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Remove useDefineForClassFields from tsconfig" accurately describes a real change present in the pull request—specifically, the removal of the explicit compiler option from editor/tsconfig.json. The title aligns with the PR description which states the objective is to "Remove useDefineForClassFields from tsconfig, use the default true value." However, the title captures only a single file modification, while the actual changeset includes extensive refactoring across 11+ component files that replace NGXS @select decorators with explicit store.select() calls in constructors. The title refers to a real aspect of the change but does not convey the main body of work (the decorator refactoring pattern applied consistently across multiple components).
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-ts-useDefineForClassFields

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
editor/src/app/sites/settings/site-settings.component.ts (1)

284-305: Fix wrong equality and add null-guard in children reuse logic

  • Bug: comparing prevChild.setting === child.config mixes types and prevents reuse; should compare setting-to-setting (or config-to-config).
  • Robustness: prevSettingChildren may be undefined; length access can throw.

Suggested diff:

-                    const prevSettingChildren =
-                      prevSettingGroup.settings[index].children;
+                    const prevSettingChildren =
+                      prevSettingGroup.settings[index].children;

-                    if (prevSettingChildren.length > 0) {
+                    if (prevSettingChildren?.length > 0) {

-                          return row.map((child, i) => {
+                          return row.map((child, i) => {
                             const prevChild = prevSettingRow[i];

-                            if (
-                              prevChild &&
-                              prevChild.setting === child.config
-                            ) {
+                            if (
+                              prevChild &&
+                              prevChild.setting === child.setting
+                            ) {
                               return prevChild;
                             }

Also applies to: 293-296

🧹 Nitpick comments (4)
editor/src/app/sites/media/entry-gallery-editor.component.ts (1)

451-486: Avoid nested subscriptions; add automatic teardown

Use RxJS composition + takeUntilDestroyed to prevent leaks and simplify flow.

Minimal change:

+import { DestroyRef, inject } from '@angular/core';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

 export class EntryGalleryEditorComponent implements OnInit {
+  private destroyRef = inject(DestroyRef);

   ngOnInit() {
-    this.route.paramMap
-      .pipe(
-        filter((p) => p['params']['section'] !== undefined && p['params']['entry_id'] !== undefined),
-      )
-      .subscribe((params) => {
-        const sectionName = params['params']['section'];
-        const entryId = params['params']['entry_id'];
-
-        combineLatest([ this.currentSite$, ... ])
-          .subscribe(([site, template, section, entry]) => { ... });
-      });
+    this.route.paramMap.pipe(
+      filter((p) => p['params']['section'] !== undefined && p['params']['entry_id'] !== undefined),
+      map((params) => ({
+        sectionName: params['params']['section'],
+        entryId: params['params']['entry_id'],
+      })),
+      switchMap(({ sectionName, entryId }) =>
+        combineLatest([ this.currentSite$, /* ... */ ]).pipe(
+          map(([site, template, section, entry]) => ({ site, template, section, entry })),
+        )
+      ),
+      takeUntilDestroyed(this.destroyRef),
+    ).subscribe(({ site, template, section, entry }) => { /* assign fields, setSelectedFile() */ });
   }
editor/src/app/app.component.ts (2)

234-246: Teardown for live subscriptions

user$, isLoggedIn$, and isSetup$ subscriptions are long‑lived but not unsubscribed. Prefer takeUntilDestroyed to avoid leaks and align with Angular 16+.

Example:

+import { DestroyRef, inject } from '@angular/core';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

 export class AppComponent implements OnInit, OnDestroy {
+  private destroyRef = inject(DestroyRef);

-    this.isLoggedIn$.subscribe((isLoggedIn) => { ... });
+    this.isLoggedIn$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((isLoggedIn) => { ... });

-    this.isSetup$.pipe(filter((isSetup) => isSetup)).subscribe(() => { ... });
+    this.isSetup$.pipe(filter(Boolean), takeUntilDestroyed(this.destroyRef)).subscribe(() => { ... });

-    this.user$.subscribe((user) => { ... });
+    this.user$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((user) => { ... });

Also applies to: 247-271


305-318: Use new Observable instead of deprecated Observable.create

RxJS 7 deprecates Observable.create. Minor cleanup:

-        return Observable.create((observer) => {
+        return new Observable((observer) => {
editor/src/app/shop/regional-costs/shop-regional-costs.component.ts (1)

165-165: Consider marking regionalCosts$ as readonly

Aligns with other files in this PR and communicates intent.

-  regionalCosts$: Observable<ShopRegion[]>;
+  readonly regionalCosts$: Observable<ShopRegion[]>;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b48fa25 and 64b0acb.

📒 Files selected for processing (14)
  • editor/src/app/app.component.ts (2 hunks)
  • editor/src/app/header/header.component.ts (2 hunks)
  • editor/src/app/header/preview-toggle.component.ts (2 hunks)
  • editor/src/app/profile-dropdown/profile-dropdown.component.ts (2 hunks)
  • editor/src/app/shop/orders/shop-orders.component.ts (2 hunks)
  • editor/src/app/shop/regional-costs/shop-regional-costs.component.ts (3 hunks)
  • editor/src/app/shop/regional-costs/shop-regional-costs.state.ts (1 hunks)
  • editor/src/app/sites/media/entry-gallery-editor.component.ts (2 hunks)
  • editor/src/app/sites/media/entry-gallery-image-editor.component.ts (3 hunks)
  • editor/src/app/sites/media/site-media.component.ts (4 hunks)
  • editor/src/app/sites/sections/background-gallery-editor.component.ts (2 hunks)
  • editor/src/app/sites/settings/site-settings.component.ts (2 hunks)
  • editor/src/app/user/auth-guard.service.ts (2 hunks)
  • editor/tsconfig.json (0 hunks)
💤 Files with no reviewable changes (1)
  • editor/tsconfig.json
🧰 Additional context used
🧬 Code graph analysis (9)
editor/src/app/profile-dropdown/profile-dropdown.component.ts (1)
editor/src/app/user/user.state.model.ts (1)
  • UserStateModel (1-19)
editor/src/app/sites/media/entry-gallery-image-editor.component.ts (1)
editor/src/app/sites/sites-state/site-state.model.ts (1)
  • SiteStateModel (1-9)
editor/src/app/shop/regional-costs/shop-regional-costs.component.ts (1)
editor/src/app/shop/regional-costs/shop-regional-costs.state.ts (1)
  • ShopRegion (44-49)
editor/src/app/header/header.component.ts (1)
editor/src/app/user/user.state.model.ts (1)
  • UserStateModel (1-19)
editor/src/app/sites/settings/site-settings.component.ts (2)
editor/src/app/user/user.state.model.ts (1)
  • UserStateModel (1-19)
editor/src/app/app-state/app-state.interface.ts (1)
  • AppStateModel (7-27)
editor/src/app/sites/sections/background-gallery-editor.component.ts (2)
editor/src/app/sites/sites-state/site-state.model.ts (1)
  • SiteStateModel (1-9)
editor/src/app/sites/sections/sections-state/site-sections-state.model.ts (2)
  • SiteSectionStateModel (1-37)
  • SiteSectionBackgroundFile (39-47)
editor/src/app/sites/media/entry-gallery-editor.component.ts (3)
editor/src/app/sites/sites-state/site-state.model.ts (1)
  • SiteStateModel (1-9)
editor/src/app/sites/sections/sections-state/site-sections-state.model.ts (1)
  • SiteSectionStateModel (1-37)
editor/src/app/sites/sections/entries/entries-state/section-entries-state.model.ts (2)
  • SectionEntry (5-11)
  • SectionEntryGalleryFile (22-32)
editor/src/app/sites/media/site-media.component.ts (1)
editor/src/app/sites/sites-state/site-state.model.ts (1)
  • SiteStateModel (1-9)
editor/src/app/app.component.ts (1)
editor/src/app/user/user.state.model.ts (1)
  • UserStateModel (1-19)
🔇 Additional comments (15)
editor/src/app/header/preview-toggle.component.ts (1)

54-62: LGTM! Clean refactor from @select decorator to constructor initialization.

The explicit observable declaration and constructor-based initialization using the named selector AppState.getLastRoute follows best practices and maintains type safety.

editor/src/app/user/auth-guard.service.ts (1)

13-20: Excellent refactor with proper visibility and immutability.

The change to private readonly is ideal for this use case since isLoggedIn$ is only used within the class and should never be reassigned. The constructor initialization with the named selector UserState.isLoggedIn maintains type safety.

editor/src/app/sites/media/entry-gallery-image-editor.component.ts (1)

127-149: Clean refactor maintaining template compatibility.

The explicit observable declaration and constructor initialization properly maintains the public visibility needed for template usage at line 166. The named selector SitesState.getCurrentSite ensures type safety.

editor/src/app/shop/orders/shop-orders.component.ts (1)

132-138: LGTM! Proper refactor of multiple observables.

Both observables are correctly declared and initialized in the constructor with their respective named selectors. The public visibility is appropriate for template usage throughout lines 12-114.

editor/src/app/sites/media/site-media.component.ts (2)

99-125: LGTM! Proper use of readonly and correct initialization.

The readonly modifier is appropriate since currentSite$ is never reassigned after constructor initialization. The named selector SitesState.getCurrentSite maintains type safety.


35-35: Correct track expression update.

The track expression correctly accesses section.section.name to match the data structure where sectionsList contains objects with a nested section property (as defined at lines 101-104).

editor/src/app/sites/sections/background-gallery-editor.component.ts (1)

329-344: Excellent refactor with improved type safety and visibility.

The private readonly modifier is ideal since currentSite$ is only used within the class (assigned to this.currentSite at line 359). The explicit boolean type annotations on lines 334-335 improve code clarity. The constructor initialization with SitesState.getCurrentSite maintains type safety.

editor/src/app/profile-dropdown/profile-dropdown.component.ts (1)

114-118: No changes needed—implementation is consistent with established codebase patterns.

The review comment incorrectly suggests using a named selector. However, verification shows that raw state access (state) => state.user is the consistent pattern throughout the codebase for accessing the full user state (used in 9+ files), while named selectors like UserState.isLoggedIn are reserved for derived values. No full-state selector exists or is expected. The code in profile-dropdown.component.ts follows the correct pattern.

Likely an incorrect or invalid review comment.

editor/src/app/header/header.component.ts (1)

122-132: Let me check the complete UserState file to see all available selectors:

The review comment appears based on incomplete information about available selectors. Verification requires access to the full UserState file.

From the script output, I found that UserState has selectors like isLoggedIn, hasFeatureShop, and hasFeatureMultisite. However, the script only showed partial context, not all available selectors. To conclusively determine whether the raw state access (state) => state.user should be replaced with a named selector, I need to see the complete user.state.ts file to verify:

  1. Whether UserState provides a dedicated selector for the full user state (e.g., @Selector() static user(...))
  2. Whether the raw access pattern is intentional or an oversight

The evidence is inconclusive because grep with context flags only showed a subset of methods. If a user selector exists in UserState, the suggestion is valid. If it doesn't exist, raw access may be the intended pattern.

editor/src/app/sites/settings/site-settings.component.ts (2)

4-4: Decorator removal and Store import — looks good

Switching from @select to Store.select aligns with the PR’s direction.


172-173: Move to readonly Observables initialized in constructor — good; verify null-safety in template calls

The change is clean and explicit. Please verify initial emissions for user$ and appState$ are never undefined when passed into methods from the template (isDisabled/disabledReason). If there’s any chance of undefined, guard in the methods or startWith a safe default.

Also applies to: 179-182

editor/src/app/sites/media/entry-gallery-editor.component.ts (1)

431-431: Constructor-based store selection and explicit typing — LGTM

  • private readonly currentSite$ via store.select: good.
  • Explicit boolean inits: good.

Also applies to: 437-438, 446-448

editor/src/app/app.component.ts (1)

144-144: Explicit store.select wiring + readonly fields — solid

Clearer initialization, reduced decorator magic, and tighter immutability. Nice.

Also applies to: 149-150, 151-156, 159-161, 168-174

editor/src/app/shop/regional-costs/shop-regional-costs.state.ts (1)

44-60: Exporting interfaces — good move

Making ShopRegion, ShopRegionalCost, and ShopRegionalCostsModel exported enables safer typing in components/selectors.

editor/src/app/shop/regional-costs/shop-regional-costs.component.ts (1)

165-165: Constructor-wired regionalCosts$ — LGTM

Direct Store.select improves clarity and avoids decorator coupling. Works well with exported ShopRegion type.

Also applies to: 185-188

@uldisrudzitis uldisrudzitis merged commit 656b104 into master Oct 29, 2025
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file Enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant