[RFC / Experiment] Full internal type system: zero any, strict flags, TS test suite (stacked on #4003) - #4004
Open
MrRio wants to merge 7 commits into
Open
[RFC / Experiment] Full internal type system: zero any, strict flags, TS test suite (stacked on #4003)#4004MrRio wants to merge 7 commits into
MrRio wants to merge 7 commits into
Conversation
…lyfills.ts - oxlint no-explicit-any/no-ts-ignore wired into npm run lint (replaces the eslint stack, which cannot run against TypeScript 7's native compiler) - Node jasmine run loads .ts specs via @babel/register + a .js->.ts require-resolution hook (works on Node 20, no native stripping needed) - karma serves test/specs/*.spec.ts through the babelTS preprocessor - typed spec globals in test/globals.d.ts, checked by test/tsconfig.json - canary: pdfname.spec.mjs -> pdfname.spec.ts runs in browser AND node - src/polyfills.js -> polyfills.ts (rollup polyfill inputs updated)
…ype support) prettier@1 cannot parse TypeScript type-only imports. .prettierrc pins arrowParens/trailingComma to the prettier-1 layout so the upgrade itself produces no formatting churn.
…nal classes - src/ typechecks clean under noImplicitAny/noImplicitThis with zero explicit any (oxlint-enforced); @ts-nocheck only in the two vendored files (WebPDecoder, ttffont) - internal function-constructors converted to ES classes: Matrix, Point, Rectangle, GState, Pattern, ShadingPattern, TilingPattern, PubSub, AcroForm hierarchy, Cell, BmpDecoder, PDFSecurity, RGBColor, GifReader/GifWriter (new-less internal construction dropped) - class fields use declare (type-only) so babel emits no class-properties transform and instance property layout stays identical - globalObject typed as globalThis + index signature; polyfill install boundaries in Blob/FileSaver typed with documented casts - runtime gate: API parity identical, node 467/0, browser 623 at baseline - fixed one conversion regression (context2d getRGBA gradient guard excluded function-typed gradient stubs) - removed dead getter-only writes from acroform.spec (strict-mode modules throw where sloppy scripts silently no-oped)
- all 62 spec files typecheck clean in the test project (noImplicitAny on) - jspdf.unit private surface typed via PrivateSurface + priv() helper - spec-discovered type gaps fixed in src/types.ts (legacy text() overload, getCreationDate overload, optional flags, private members) - top-level jsPDF global reads made lazy for the Node run - typescript deployment suite rewired to compare.ts - CONTRIBUTING: phase-2 conventions (declare fields, no-any policy, augmentation pattern, TS test system) - repo-wide prettier 3 formatting pass
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 #4003 (
typescript-port). Review only the commits after543e1f7a. Like its base, this is an experiment/RFC — but it answers the question the base PR deliberately deferred: what does jsPDF look like with a real type system?What this does
Phase two of the TypeScript port: replaces the mechanical port's
any-scaffolding with a full internal type system, converts the test suite to TypeScript, and turns on the strictness the base PR left off.src/types.ts— the internal type system:jsPDFDocument,jsPDFAPI(the plugin surface),jsPDFInternal,Matrix,Font,PageInfo, options/output types, PubSub, patterns. Each plugin module declares the members it adds viadeclare module "../types.js"interface augmentation in its own file, sodoc.internal, plugin methods, andthisinside plugins are all real types with autocomplete.any, enforced in lint.npm run lintnow runs oxlint withno-explicit-any+no-ts-ignoreas errors acrosssrc/and the test suite (@typescript-eslintcannot run against TS7's native compiler — it needs the removed JS API — so the old eslint stack is replaced by oxlint).noImplicitAnyandnoImplicitThisare ON. The ~2,600-error burn-down is complete: the only escape hatches are ~200 documentedas unknown ascasts at genuine dynamic boundaries (polyfill installs over DOM types, negative tests feeding invalid inputs, the__private__test surface) and two vendored files that stay@ts-nocheck(minified libwebp, compiled-CoffeeScript ttffont).Matrix,Point,Rectangle,GState,Pattern,ShadingPattern,TilingPattern,PubSub, the whole AcroForm field hierarchy,Cell,BmpDecoder,PDFSecurity,RGBColor,GifReader/GifWriter. Constructing them withoutnewno longer works (jsPDF()itself still supports new-less calls). Class fields aredeclare-only so babel emits no class-properties transform and instance property layout is byte-compatible..spec.ts, type-checked bytest/tsconfig.jsonas part ofnpm run typecheck— every spec is now also a continuous typings test. Browser runs strip types via the karmababelTSpreprocessor; the Node jasmine run uses@babel/registerwith a.js→.tsresolution hook (works on Node 20, no native stripping needed). Source-importing lib specs moved totest/specs/libs/and are excluded from dist-facing deployment/Node runs..jsreduced further:polyfills.tsconverted; thefflate/fast-pngshims stay JS deliberately (karma's rollup preprocessor serves them by on-disk path). prettier upgraded to v3 (v1 cannot parseimport type), with.prettierrcpinned so the upgrade itself produced no layout churn.The types found real bugs
The strict pass surfaced (and deliberately preserved, with comments) six more latent bugs on top of the base PR's three — e.g.
addSvgAsImageforwards its arguments one slot early intoaddImage, and the outline plugin passes a string object-id where a number is expected. The specs also exposed ten places where the shippedtypes/index.d.tsdisagrees with the implementation (Font.idis a string,output("bloburi")returns a string, missingMatrixgetters…). With this branch, those can't drift again: declarations could now be generated from source and the 1,471-line hand-written file retired.Verification
Same gates as the base PR, all green:
npm run typecheck(src + test projects,noImplicitAny/noImplicitThis) at 0 errors;npm run lint(prettier 3 + no-any) clean; API-parity script reports the surface identical to pre-port master (17 exports / 5 statics / 65 API keys / 170 instance+prototype keys); Node suite 467/0; browser suite 623 at the known environmental baseline; all five deployment suites at baseline;test-typingspasses.What's deliberately NOT here
strictNullChecksstays off — it's the one remaining strictness gap and a large, separately-reviewable burn-down. The hand-writtentypes/index.d.tsstill ships unchanged (retiring it in favor of generated declarations is the natural follow-up once this lands).