[RFC / Experiment] Enable strictNullChecks — full strict mode (stacked on #4004) - #4005
Open
MrRio wants to merge 3 commits into
Open
[RFC / Experiment] Enable strictNullChecks — full strict mode (stacked on #4004)#4005MrRio wants to merge 3 commits into
MrRio wants to merge 3 commits into
Conversation
…ange - 472 src errors + 72 spec errors to zero under strictNullChecks - techniques: honest nullable types (loadFile/processJPEG/getFont returns, acroform fields, canvas setters, table data param), control-flow-faithful narrowing, non-null assertions with invariant comments, and definite-assignment assertions; NO new runtime guards or defaults - no new 'as unknown as' casts (user directive); two obsolete phase-2 casts removed where honest types made them unnecessary - getPageInfo internal signature honestly widened to number | string (its validation coerces; getPageInfoByObjId passes for-in keys)
- all 199 double-assertions removed from src and test - src: reality declared instead of asserted — ambient namespace merging for jsPDF static slots (__bidiEngine__, getPageSize), overloaded function declarations for output/save/text/getCreationDate implementations, honest widenings (addImage compression slot, newObjectDeferredBegin, CharWidthsOptions.font), jsPDFPrivate is now a fully-declared ~70-member interface, GState carries its real reflective index signature - irreducible boundaries (polyfills overwriting DOM types, vendored-opaque constructors) use named unknown-typed intermediates with single assertions — the chain pattern is gone everywhere - tests: new sanctioned primitive invalidArg<T>() (runtime identity, declared in test/globals.d.ts, defined in test/utils/compare.ts) for deliberately-invalid negative-test inputs; receiver-preserving casts where methods are involved (this-binding survives) - lint-no-unsafe-cast greps the tree and fails on any reintroduction, chained into npm run lint
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Stacked on #4004 (
typescript-internal-types), which stacks on #4003. Review only the commits after the phase-2 head. This completes the strictness story: with this PR, jsPDF compiles under the fullstrictflag set.What this does
Enables
strictNullChecks— the one flag phase 2 deferred — and burns down the resulting 472 source errors and 72 spec errors to zero, with a hard rule enforced throughout: zero runtime behavior change. No new null guards, no default fallbacks, no early returns. The permitted tools were:loadFile()returnsstring | undefined,processJPEG()returnsImageProperties | null, AcroForm'sRect/Qfields are clearable, canvaswidth/heightsetters accept (and sanitize) anything,table()'s data param admitsundefinedbecause throwing"No data for PDF table."is its documented contract.undefined > 0 === falsebecomes an explicit!== undefined &&with identical truth table;isNaN(undefined) === truepaths kept as ternaries).!) where a real invariant guarantees presence — each non-obvious one carries a comment naming the invariant (event ordering, prereq chains, "first loop iteration assigns"). Deliberately-preserved legacy NaN-propagation arithmetic is asserted, not guarded.Also per project policy on this stack: no new
as unknown ascasts anywhere in this diff (and two phase-2 casts became removable once the underlying types were honest, so they're gone).Verification
Same gates as the stack, all green:
npm run typecheck(src + test projects, now fullystrictexcept nothing — every strict flag is on) at 0; lint (prettier + no-any/no-ts-ignore) clean; API parity identical to pre-port master; Node suite 467/0; browser suite 623 at the known environmental baseline; all five deployment suites at baseline;test-typingspasses.Notes for review
getPageInfo's validation genuinely coerces numeric strings, so its internal signature says so instead of hiding it behind a cast).cell.ts/context2d.tspreserve some subtle legacy semantics on purpose: undefined/NaN propagation in cell arithmetic, and the mid-loop re-read oftableHeaderRowduring recursive header printing.types/index.d.tsfrom source and retire the hand-written file.Addendum: the
as unknown aspurgeAll 199 double-assertions inherited from phase 2 are now gone from
src/and the test suite, and a lint guard (lint-no-unsafe-cast, chained intonpm run lint) fails the build if the pattern ever returns.How they died, by category:
__bidiEngine__,getPageSize) get ambient namespace-merged declarations;output/save/text/getCreationDateimplementations are now properly-overloaded function declarations;jsPDFPrivategrew from an index signature to a fully-verified ~70-member interface (every member checked against the implementation); several signatures were honestly widened where the implementation genuinely accepts more (addImage's compression slot — which also surfaces theaddSvgAsImagearg-shift latent bug in the type —newObjectDeferredBegin, kerning tables).invalidArg<T>(value: unknown): T— runtime identity, defined once intest/utils/compare.ts. Deliberately-invalid inputs are now greppable and self-describing (receiver-preserving at method call sites sothis-binding survives — one purge regression was caught by the suite exactly this way and fixed).unknown-typed intermediate plus a single assertion. The laundering that remains is minimal, local, named, and commented — and the lint guard keeps it from ever silently spreading again.Gate re-verified after the purge: both projects typecheck clean, lint (including the new guard) passes, API parity identical, Node 467/0, browser + all deployment suites at baseline.