Skip to content

chore(express): remove redundant option-object casts - #114

Merged
Bccorb merged 1 commit into
mainfrom
chore/remove-option-casts
Jul 21, 2026
Merged

chore(express): remove redundant option-object casts#114
Bccorb merged 1 commit into
mainfrom
chore/remove-option-casts

Conversation

@Bccorb

@Bccorb Bccorb commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Removes all 41 as any / option-object casts from the Express adapter so the compiler checks each option literal against its handler interface. These casts are the exact construct that let the getSeamlessUser serviceAuthorization option be silently dropped (#99): the cast disables excess-property checking, so a mistyped or renamed option compiles clean and vanishes at runtime.

Closes #106.

What was hidden

Exactly as the #106 audit predicted, only one cast was hiding anything real: a dead forwardedClientIp: undefined property on the createEnsureCookiesMiddleware options literal, which is not in EnsureCookiesMiddlewareOptions (the real value is computed per request inside the middleware). Removing the cast surfaced it as a compile error; it is now deleted. Every other literal type-checks cleanly against its interface, confirming none currently drops a live option.

The metrics query cast

internalMetrics.ts used query: req.query as any. Express types req.query as ParsedQs, which genuinely is not the scalar Record<string, string | number | boolean | undefined> the core handler declares, so this cast was doing real (if unsound) work. Replaced with a toQueryRecord normalizer rather than another cast.

One visible edge case worth calling out: previously an array-valued query param (?type=a&type=b) reached the upstream comma-joined via String(['a','b']). The scalar handler contract never supported arrays, and the normalizer now takes the first value. Metrics filters are scalar by design (date ranges, group-by keys), so this only affects an input the contract never modeled.

Not a cast

clientErrorStatus's err as { status?: unknown } narrowing and the result: any handler params are legitimate and untouched. Scope was strictly the option-literal casts.

Checks

core:    18 suites, 84 tests passed
express: 25 suites, 133 tests passed
build:   both packages Done (type build clean)

Identical test counts to before, confirming no behavior change. No em dashes. Changeset included (patch, express).

Strip the as any and as SomeOptions casts on the option literals passed
to the core handlers. These casts disabled excess-property checking, which
is what let a mistyped option be silently dropped in the getSeamlessUser
regression. Removing them lets the compiler check each literal against its
handler interface.

Delete the dead forwardedClientIp: undefined property on the ensureCookies
middleware options (the value is computed per request), and replace the
blanket req.query cast in the metrics handlers with a small normalizer that
reduces Express's ParsedQs to the scalar query record the core handler
declares. No public API change.
@Bccorb
Bccorb merged commit 682c9f8 into main Jul 21, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove redundant option-object casts in the Express adapter

1 participant