Forger Help

Caveats

Known sharp edges. All of them are consequences of the compile-time design — understanding them makes Forger predictable.

Without the transformer, everything is undefined

Forger.create<T>() receives its type information from the transformer. If the build does not apply it, the call returns undefined — that is what the T | undefined signature reflects.

Checklist: plugins entry in tsconfig, ts-patch/compiler in ts-jest, transformer in astTransformers — see Installation. A suite that suddenly returns undefined everywhere is a wiring problem, not flaky data. After changing transformer configuration, clear the Jest transform cache (jest --clearCache) — a stale cache keeps serving spec files compiled without the transformer.

One TypeScript instance per build

Forger's transformer resolves the typescript package installed next to your project. If the module tree contains more than one TypeScript copy (nested installs, symlinked local packages), the transformer may load a different compiler instance than the one building your code — and silently produce no transformation. Keep a single typescript in node_modules (npm ls typescript to verify).

Standalone literal types forge to null

Forger.create<'fixed'>(); // null

Literals work only as union members — see Literals.

Class methods are forged as data, not callables

A method declaration (greet(): string) becomes a string property holding a forged return type. Calling it fails. Use function-typed properties (greet: () => string) or pin a real function — see Functions.

Fields without a type annotation forge to null

bar = 5 gives the transformer nothing to read; the property is present but null. Annotate: bar: number = 5.

Built-in structural types are forged structurally

Map, Set, Promise and friends are treated as ordinary object types: their members — mostly methods — become forged data properties (see Objects). The result type-checks but does not behave. Pin real instances where behavior matters.

with() affects only the root instance

Properties pinned through createWith are excluded from generation for the root type instance only — same-named properties in nested objects (even of the same type) are still generated. See createWith.

Union rolls are random per call

A union-typed value may be a different member on every run. If a test is about a specific member, pin it or narrow the type argument.

Never pass the trailing argument

create and createWith accept a trailing technical argument injected by the transformer (the serialized type description). Passing anything there manually breaks generation.

08 September 2026