Handing a rule to the compiler: the mutation 2347 tests could not see

Which rules move into the type system, and which only a test can hold.

There was a union type with seven members and two predicates that answer a question for each member. Adding an eighth member left tsc --noEmit at exit 0 and left 2347 of 2347 tests green, because both tests asserted the seven known members one by one and the eighth broke no assertion. Once the expected values were held as Record<Overlay, boolean> instead, the same mutation fails the typecheck with exit 2 and exactly two TS2741 errors, one in each test file. Where the red appears matters: vitest still runs those two files green, and the gate is the typecheck step rather than the suite. The limit belongs in the same breath, since the map says every member has been answered, not that the answer is right.

Rules only a test can hold

Other rules can only be held by a test. A pure layout module was required to carry zero imports; adding a single import type line to it left the typecheck at exit 0 and turned exactly one of 2473 tests red, and that one was the structural gate written for this very rule, so 2472 assertions were blind to it. Narrowing a persisted record sits between the two cases: narrowing the partialize field alone was not enough, because the defect lives in bytes already written on the visitor's disk. Three independent mutations each felled a different assertion. Taking the version from 2 back to 1 brings the windows back, deleting migrate makes zustand discard the stored record entirely, and a migrate that spreads the stored record brings the windows back again. A security pass found the bonus: the old record carried window targets, so which project and post addresses a visitor had opened were sitting on disk, and today only two integers remain there.

Tags

  • TypeScript
  • Testing
Handing a rule to the compiler: the mutation 2347 tests could not see · Deniz Barış Yıldırım, Portfolyo OS