Skip to content

refactor(ts): migrate deserializer to TypeScript with typed distribution - #202

Open
tvdeyen wants to merge 3 commits into
mainfrom
typescript-pipeline
Open

refactor(ts): migrate deserializer to TypeScript with typed distribution#202
tvdeyen wants to merge 3 commits into
mainfrom
typescript-pipeline

Conversation

@tvdeyen

@tvdeyen tvdeyen commented Aug 21, 2026

Copy link
Copy Markdown
Member

Migrates the deserializer to TypeScript and ships type declarations so consumers get types and editor support (including the @deprecated hints on deserializePage/deserializePages added in #201).

Sourcedeserialize, alchemyApiDeserializer and the barrel become .ts. Behaviour is unchanged; the existing specs (migrated to .ts) still pass, and the folded numeric-id/absent-to-many case keeps the coverage the old deserialize.spec.js had.

Distribution pipelinebuild now runs vite build for the JS bundles plus tsc --emitDeclarationOnly for the .d.ts. A tsconfig.json (strict, lib: ["ES2022","DOM"] for structuredClone) drives declaration emit and a new typecheck script. package.json gains a types field and an exports map exposing types for both the root entry and the ./deserialize subpath.

Public type surface — the JSON:API document shapes are kept internal (not exported). deserialize is <T = unknown>(document: unknown): T, so those shapes aren't part of the contract; exporting them would only add generically-named types (JsonApiResource, JsonApiDocument, …) that could collide with a consumer's own definitions. The emitted deserialize.d.ts therefore exposes only deserialize.

Based on main (after #200 and #201).

@tvdeyen
tvdeyen force-pushed the typescript-pipeline branch 2 times, most recently from 48332cf to 69e83bb Compare August 21, 2026 09:02
Convert the deserializer, alchemyApiDeserializer and barrel to TypeScript
and add a declaration pipeline so consumers get types. The build now runs
vite for the JS bundles plus `tsc --emitDeclarationOnly` for the .d.ts
files, and package exports expose types for both the root entry and the
./deserialize subpath.

The JSON:API document shapes stay internal (not exported): the public
entry point takes `unknown`, so exporting them would only add
generically-named types that could collide in consuming apps. Specs move
to .ts; the single non-redundant case from deserialize.spec.js is folded
into deserialize.spec.ts so no coverage is lost.
@tvdeyen
tvdeyen force-pushed the typescript-pipeline branch from 69e83bb to 09cae85 Compare August 21, 2026 09:07
deserialize re-expanded every reference path, so a resource reachable via
many paths was rebuilt at each one. On densely cross-linked documents — e.g.
a navigation menu whose nodes link parent <-> children — this grew super-
linearly: a 0.57 MB payload produced a 12 MB graph in ~60 ms.

Resolve each resource once and share it by reference, stubbing only true
cycles (a reference to a resource still being resolved). The graph stays
acyclic and every resource is still fully present; the same payload now
yields 0.80 MB in ~3 ms. `{ expand: true }` keeps the previous per-path
full expansion for callers that need a fully-expanded object at every path.
Update the frontend usage to deserialize (deserializePage/Pages are now
deprecated aliases) and explain how references resolve: relationships
become nested objects or { id } stubs, the graph is acyclic by
construction via grey/black DFS marking, and { expand: true } opts into
full per-path expansion.
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.

1 participant