Skip to content

Enable noUncheckedIndexedAccess in app tsconfigs

Problem

Shared packages (widget-wire-schemas, widget-renderers, portable-text) already set noUncheckedIndexedAccess: true, but the apps' tsconfigs do not. This means arr[i] and map.get(k) are inferred as their element type with no | undefined, hiding a class of runtime bugs.

Proposal

  1. Enable noUncheckedIndexedAccess: true in both app tsconfigs.
  2. Run npm run typecheck and fix fallout iteratively. Expected hotspots:
    • Pagination helpers slicing arrays.
    • Map-based RBAC lookups in apps/cms/src/lib/rbac/*.
    • Kysely result destructuring (rows[0]).
  3. Use explicit guards (if (!row) throw ...) rather than non-null assertions where possible. Where a non-null assertion is genuinely correct, add a brief comment explaining why.
  4. Do not introduce // @ts-expect-error to silence failures.

Acceptance criteria

  • noUncheckedIndexedAccess: true set in both app tsconfigs (and packages/ui).
  • npm run typecheck is green for both apps.
  • No new // @ts-ignore / // @ts-expect-error added.
  • npm run check passes.

Out of scope

  • Tightening other strictness flags (exactOptionalPropertyTypes, noPropertyAccessFromIndexSignature).
  • Refactoring code beyond what the new check forces.

Notes / decisions log

  • 2026-05-24: Ticket created from monorepo audit.
  • 2026-05-25: Implemented bundled with T-008: enabled flag on apps/lms, apps/cms, and packages/ui; fixed ~58 LMS and ~393 CMS indexed-access errors; added shared getInitials at @open-learning-hub/ui/lib/get-initials; CMS test helpers (src/test/expect-defined.ts, kysely-chain-mock.ts, store-test-helpers.ts). Re-rated effort medium (CMS Zustand stores + test fixtures dominated lift).