Skip to content

Turn on noUncheckedIndexedAccess, one package at a time #774

Description

@InfinityBowman

None of the five tsconfigs set noUncheckedIndexedAccess. It is the flag that would have surfaced the requireQuota fail-open without anyone going looking for it.

Why

strict: true is on in web, workers, shared, and db -- good baseline. But indexed access still lies:

const limit = quotas[quotaKey];   // typed number, actually undefined

That is the mechanism behind the quota guard defect. The flag makes the type number | undefined and forces the check.

Approach

Per package, smallest surface first:

  1. packages/db
  2. packages/shared
  3. packages/workers
  4. packages/web (will be noisy)

exactOptionalPropertyTypes is the natural follow-up -- it is what makes "? means absent, | null means nullable" enforceable rather than a convention -- but the fallout is much larger. Treat it as a separate decision after this one lands, not part of this issue.

Done when

  • noUncheckedIndexedAccess: true in all four tsconfigs
  • pnpm typecheck clean

Effort: roughly half a day per package, concentrated in web.


Prerequisite: #779

Do #779 first. There is no shared tsconfig base today -- four packages restate their options independently and have already drifted -- so turning this flag on per package means four edits that will drift again. One base config all four extend is the same work with a durable result.

The trap: do not pay the tax in !

This flag's cost is non-null assertions. Every indexed access becomes T | undefined, and the shortest way to silence each one is arr[i]! -- which re-suppresses exactly what the flag just surfaced. Turning on the flag and then !-ing the fallout is net-negative: the same unchecked claim, now with more ceremony.

cf-sync-engine has had this flag on since its first commit and carries 27 ! assertions in 6,549 lines as the honest cost -- payload[0]!, values[i]!, migrations[i - 1]!.to. Most sit in loops where the bound is provable a line or two away. That is the acceptable rate and the acceptable shape.

Set the rule before starting: fix with a check or a narrow; reach for ! only when the bound is provable within a few lines, and never across a function boundary. If a package's fallout cannot be fixed that way, that is a finding worth writing down, not a reason to bulk-assert.


Part of #778 (TypeScript correctness target state and tracker).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions