kit icon indicating copy to clipboard operation
kit copied to clipboard

Refactor app-launcher.ts for Type Safety and Maintainability

Open johnlindquist opened this issue 1 month ago • 0 comments

Refactor app-launcher.ts for Type Safety and Maintainability

Overview

Code review of src/main/app-launcher.ts revealed critical issues with type safety and architectural patterns that make the code fragile and difficult to maintain.

🔴 Critical Issues

1. Imperative State Mutations Throughout

The code uses imperative mutations (setResize(), setChoices(), clearTabs(), setPlaceholder()) instead of declarative state management, making state transitions unpredictable.

Lines affected: 24-35, 62

Impact: UI behavior is difficult to reason about and debug. State changes are scattered throughout the code with no clear data flow.

2. Type Safety Completely Absent

Pervasive use of any, missing type annotations, and type erasure defeats TypeScript's purpose.

Lines affected: 48, 73

let app = await arg(
  { /* config */ },
  appsDb.choices as any  // 🚨 Type erasure!
)

Impact:

  • No IDE autocomplete
  • No compile-time safety
  • Refactoring tools cannot safely rename properties
  • Runtime errors waiting to happen

3. Side Effects Without Clear Data Flow

Lines 17-19 and 45-46 have conditional side effects based on flags with no clear data flow.

if (!flag.prep) {
  preload()  // What does this mutate? When? Why?
}

🟡 Major Issues

4. Callback Hell and Hidden Side Effects

The onPress callback (lines 61-69) has nested side effects and async operations that mutate external state.

5. Type-Unsafe Flag Access

Lines 17, 42, 45, 51 access flag properties with optional chaining but no type definitions.

if (!flag.prep) { ... }          // What type is flag?
if (flag?.prep) { ... }          // Inconsistent access pattern
input: (flag?.input as string)   // Type assertion = type danger

6. Database Callback Pattern is Unclear

Lines 21-43 use a callback pattern for db() that mixes initialization, loading state, and data fetching without clear separation of concerns.

Proposed Solution

Phase 1: Add Type Safety

  1. Define interfaces for all data structures:
    • AppChoice
    • ArgOptions
    • FlagOptions
    • AppsDatabase
  2. Remove all as any casts
  3. Add return type annotations to all functions
  4. Type the arg() function properly

Phase 2: Extract Stateful Logic

  1. Separate data fetching from UI updates
  2. Create clear, typed state transitions
  3. Document what each function mutates and returns
  4. Make data flow explicit and unidirectional

Phase 3: Refactor for Maintainability

  1. Extract shortcuts configuration
  2. Separate concerns (data/UI/business logic)
  3. Add JSDoc comments for complex flows
  4. Consider functional patterns where appropriate

Priority Fixes (Quick Wins)

  1. Type the entire file - Add interfaces for all data structures
  2. Remove as any casts - Properly type the arg() function and choices
  3. Add return type annotations - Especially for async functions
  4. Document flag mutations - What does preload() do? When is it called?

Acceptance Criteria

  • [ ] All variables and functions have explicit type annotations
  • [ ] Zero uses of any or type assertions
  • [ ] Clear separation between data fetching and UI updates
  • [ ] Data flow is explicit and documented
  • [ ] All side effects are documented and predictable
  • [ ] IDE provides full autocomplete and refactoring support

Related Files

  • src/main/app-launcher.ts (primary file)
  • Any shared type definitions for arg(), db(), flag global

Labels

refactoring, type-safety, tech-debt, developer-experience

johnlindquist avatar Nov 07 '25 02:11 johnlindquist