Ecosystem ↗

TypeScript tooling

Separate transpilation, typechecking, loaders and bundling.

↗ View Markdown

Transpile and check separately#

ts
import { transformTypescript, checkTypes } from '@zeruxjs/typescript';
const output = transformTypescript('const answer: number = 42;');
const result = checkTypes({ files: ['src/index.ts'] });
if (!result.ok) console.error(result.diagnostics);

A successful transpile only proves syntax can become JavaScript. It does not prove type correctness. Run a separate check in development/CI and before production builds.

Build and configuration#

buildTypescript supports esbuild bundling with explicit entry points/outdir. createTsConfig creates a config only when none exists. Use the typed /presets and /tsconfig public subpaths for environment-specific generation (see below). Review generated options against the application's module/runtime requirements rather than replacing an established tsconfig blindly.

Loading modes#

registerTypescript installs CommonJS require hooks and returns a disposer. It does not enable ESM loading. The separate @zeruxjs/typescript/loader entrypoint integrates with Node's custom ESM loader mechanism. Zerux's application CLI registers its own framework loader for virtual imports and source handling.

Install and select the integration#

sh
npm install @zeruxjs/typescript@0.0.4

There is no automatic typescript startup service in zerux.config.js for this package. Import its public APIs and create the object or browser controller in the application owner that needs it. If a config object holds custom settings, your plugin/application code must explicitly consume them. See configuration integration boundaries and TypeScript.

A practical integration workflow#

Choose transform, build, typecheck or loader registration deliberately. Transforms/bundles remove syntax and may optimize output; only a separate typecheck reports semantic type errors. Browser bundles must use platform browser and a browser target; default platform remains Node. Avoid pulling filesystem/secret-bearing modules into browser entry points.

TypeScript: inputs, results and ownership#

ts
import { buildTypescript } from '@zeruxjs/typescript';

type Inputs = Parameters<typeof buildTypescript>;
type Result = Awaited<ReturnType<typeof buildTypescript>>;

Inputs is the function's complete argument tuple, including optional parameters. Result removes a Promise when the function is asynchronous. These aliases follow the installed declarations; no internal src/dist import is required. For a generic factory, keep the concrete call's inferred type when an application needs a narrower result than ReturnType preserves. Use satisfies or a public option type for configuration literals, and validate unknown request/file data separately.

In a JavaScript application the equivalent editor annotation is /** @type {Parameters<typeof buildTypescript>} */ on a matching argument tuple. This provides diagnostics only when JavaScript checking is enabled. It does not validate network data or create a resource automatically. See strict application setup for the complete NodeNext checker configuration.

Failure modes and resource lifetime#

CommonJS registration returns a disposer and does not register an ESM loader. Use the supported ESM loader mechanism for ESM TypeScript files. Output paths must not equal the source project root. Verify source maps, external packages and generated ESM/CJS format against the actual runtime. A successful transpilation does not prove package exports, types or integration behavior.

Verify before deploying#

  • Exercise the example with the actual owning runtime/browser, not only an imported module.
  • Test one invalid input and the relevant unavailable/denied dependency path; do not turn those into a silent success.
  • Confirm teardown leaves no owned listeners, timers, connections or stale per-user state.
  • Check the production entry point and installed export map; a workspace checkout can contain features not yet published to npm.

Public option and data contracts#

These tables list fields declared directly on the named public contract. Referenced/inherited types retain their own declarations; optional does not imply a default value. Use the lifecycle and configuration chapters above for actual initialization behavior.

TypeScriptBuildOptions#

Field Accepted type/value Optional
entryPoints string[] No
outdir string No
cwd string Yes
format "esm" | "cjs" | "iife" Yes
platform "node" | "browser" | "neutral" Yes
target string Yes
bundle boolean Yes
minify boolean Yes
sourcemap boolean Yes
external string[] Yes
signal AbortSignal Yes

TransformOptions#

Field Accepted type/value Optional
filename string Yes
format ScriptFormat Yes
sourceMap boolean Yes
target ts.ScriptTarget Yes

TsConfigOptions#

Field Accepted type/value Optional
preset TypeScriptPresetName Yes
overwrite boolean Yes
compilerOptions Record<string, unknown> Yes
include string[] Yes
exclude string[] Yes

TypecheckOptions#

Field Accepted type/value Optional
files string[] No
cwd string Yes
configFile string Yes
checkDependencies boolean Yes
signal AbortSignal Yes
cancellationToken ts.CancellationToken Yes

Environment presets and declaration ownership#

ts
import { createTsConfig } from '@zeruxjs/typescript/tsconfig';
import { createTypeScriptPreset } from '@zeruxjs/typescript/presets';
import { checkTypes } from '@zeruxjs/typescript';

const preset = createTypeScriptPreset('node-server');
createTsConfig(process.cwd(), { compilerOptions: preset.compilerOptions, include: preset.include });
const result = checkTypes({ files: [], checkDependencies: true });
if (!result.ok) {
  console.error(result.status, result.diagnostics);
  process.exitCode = 1;
}

The factory returns fresh typed JSON; configuration generation is explicit and leaves existing files untouched unless overwrite is requested. Compiler option overrides are validated before writing. Presets enable strict checks, skipLibCheck:false, noUncheckedSideEffectImports:true, declaration emission, noEmitOnError, local src/dist paths and export-map-aware resolution. Run tsc -p tsconfig.json in the owning package to emit declarations. Neither checkTypes nor esbuild emits declarations. The tooling package does not collect or reexport other packages' public types.

Preset Modules/resolution Globals and conditions
node-server NodeNext/NodeNext ES2022, explicit Node types; implicit node/types/import-or-require conditions
browser-library ESNext/Bundler ES2022 + DOM/DOM.Iterable, types:[], additional browser condition
mixed-exports NodeNext/NodeNext Portable ES2022 only, types:[]; implicit NodeNext conditions

Install the Node typings in the server owner. Mixed packages should separately check server/browser trees and maintain their own conditional exports and matching declarations; the portable preset is not a dual-format build generator. NodeNext's node condition cannot be removed by adding browser. The browser preset uses Bundler resolution to avoid it; browser dependencies therefore require bundling. types:[] blocks ambient Node globals but cannot block explicit Node-typed imports. Check the browser bundle separately to reject Node built-ins. Presets alone do not prove native-browser runtime resolution.

Actionable failures and cancellation#

Results retain ok and raw TypeScript diagnostics, plus status:'passed'|'failed'|'cancelled'. Compiler diagnostics cover invalid subpaths, missing declarations and config/semantic failures. Opt-in checkDependencies:true adds 95001 diagnostics for undeclared literal bare imports and 95002 for invalid owning manifests. Each local source uses its nearest manifest; dependency, dev, peer and optional declarations are accepted. Built-ins, relative paths, #imports and self-imports remain compiler-resolved. This is not a production dependency classification or computed-import audit. Do not use source paths aliases as evidence of a working installed package; check its packed exports.

A supplied AbortSignal returns cancelled/false with its reason for checks. Typechecking is synchronous, so cancellation only works at cooperative checkpoints; a TypeScript cancellationToken can also signal synchronously. Unexpected errors propagate. Build signals reject with AbortError and preserve cause details; ordinary esbuild errors retain errors/warnings. Every owned build context and abort listener is disposed. Builds are not atomic and may leave output after failure/cancellation; stage and promote when required. Browser's default target is ES2022; Node/neutral remain node20. CommonJS disposers are idempotent and invalid extension lists do not partially install hooks.

The package-local foundation tests install packed built exports offline, check a declaration consumer without source aliases, compile representative environment fixtures, and exercise invalid imports, undeclared dependencies, failed checks, cancellation and cleanup. Installed dependencies and esbuild's native platform binary are required; no application restart or live browser check is implied.

Public entry points

Manifest reference for @zeruxjs/typescript@0.0.4. Each target describes a published entry, not automatic framework registration.

ImportTarget
@zeruxjs/typescript
{
  "types": "./dist/index.d.ts",
  "import": "./dist/index.js"
}
@zeruxjs/typescript/loader
{
  "types": "./dist/loader.d.ts",
  "import": "./dist/loader.js"
}
@zeruxjs/typescript/build
{
  "types": "./dist/build.d.ts",
  "import": "./dist/build.js"
}
@zeruxjs/typescript/presets
{
  "types": "./dist/presets.d.ts",
  "import": "./dist/presets.js"
}
@zeruxjs/typescript/tsconfig
{
  "types": "./dist/tsconfig.d.ts",
  "import": "./dist/tsconfig.js"
}
Runtime requirements and dependencies
{
  "engines": {},
  "dependencies": {
    "@types/node": "^25.4.0",
    "@types/ws": "^8.18.1",
    "esbuild": "^0.28.2",
    "typescript": "^5.9.3"
  },
  "peerDependencies": {},
  "bin": {}
}
Full package README

@zeruxjs/typescript#

TypeScript transpilation, typechecking, tsconfig generation, CommonJS compatibility and optional esbuild bundling.

ts
import { transformTypescript, checkTypes, buildTypescript, createTsConfig } from '@zeruxjs/typescript';
const { code } = transformTypescript('const answer: number = 42;');
const { ok, diagnostics } = checkTypes({ files: ['src/index.ts'] });
await buildTypescript({ entryPoints: ['src/index.ts'], outdir: 'dist', bundle: true });
createTsConfig(process.cwd()); // leaves an existing config untouched

registerTypescript() installs and returns a disposer for CommonJS require hooks only. ESM TypeScript loading uses @zeruxjs/typescript/loader with Node's custom ESM loader mechanism. Transpilation does not typecheck; call checkTypes separately. buildTypescript requires esbuild, which is an explicit package dependency.

Browser production assets#

buildTypescript({entryPoints, outdir, cwd, platform:'browser', format:'esm', target:'es2022', bundle:true, minify:true, sourcemap:false}) bundles browser JavaScript or CSS entry points. The platform defaults to node for backward compatibility. Use browser output with a module script, keep browser-only APIs out of server startup code, and run a separate typecheck. The documentation site uses this API for its production CSS/JavaScript.

Typed configuration presets#

Presets are reusable JSON configuration, available from the browser-safe @zeruxjs/typescript/presets subpath. They contain tooling options only: each package continues to own its public types, declaration files and package.json export map. No service, hook or optional integration starts on import.

ts
import { createTsConfig } from '@zeruxjs/typescript/tsconfig';
import { createTypeScriptPreset } from '@zeruxjs/typescript/presets';
import { checkTypes } from '@zeruxjs/typescript';

const preset = createTypeScriptPreset('node-server'); // fresh, typed JSON options
createTsConfig(process.cwd(), { compilerOptions: preset.compilerOptions });
const result = checkTypes({ files: [], checkDependencies: true });
if (!result.ok) {
  console.error(result.status, result.diagnostics);
  process.exitCode = 1;
}

For the preset's complete include/exclude patterns (including .mts/.cts), use createTsConfig(process.cwd(), {preset:'node-server'}). Existing configs remain untouched unless overwrite:true is explicit. Overrides in compilerOptions win; invalid compiler options reject before writing. Configs are trusted local build inputs. Run tsc -p tsconfig.json in the owning package to emit its own JavaScript/declarations; checkTypes never emits and esbuild emits no declarations.

Preset Resolution and conditions Environment
node-server module/moduleResolution: NodeNext; TypeScript selects types, node, and per-import import/require conditions ES2022, explicit types:['node']; install @types/node in the owner
browser-library ESNext/Bundler, extra browser condition; respects package exports ES2022 + DOM/DOM.Iterable, types:[]
mixed-exports NodeNext as above, no extra conditions ES2022 only, types:[]; portable shared code

All presets enable strict checking, declaration emission, noEmitOnError, skipLibCheck:false, noUncheckedSideEffectImports:true, rootDir:'src' and outDir:'dist'. They never rewrite a package's exports or generate a dual ESM/CommonJS build automatically. For mixed packages, compile/check server and browser entry trees separately with the corresponding presets and package-local include/output overrides, then maintain conditional exports and declarations in that package. The portable mixed preset alone cannot certify environment-specific entries.

TypeScript custom conditions are additive: NodeNext always retains its node condition. The browser preset therefore uses Bundler resolution; it requires a bundler for browser dependencies and does not prove native browser URL resolution. Explicit types:[] prevents ambient Node globals leaking in from visible @types packages, but is not an import sandbox: explicitly importing Node-typed modules can bring their declarations in. Use a separate browser bundle check to reject Node built-ins.

Diagnostics and cancellation#

checkTypes retains {ok,diagnostics} and adds status:'passed'|'failed'|'cancelled'. Failed checks include raw TypeScript syntax, semantic, config and resolution diagnostics (including invalid/nonexported subpaths and missing declaration files). Set checkDependencies:true to also check literal bare imports/reexports, dynamic imports and require calls against each local source's nearest package.json. Diagnostic 95001 means an imported package is undeclared; 95002 means its owner manifest is missing/invalid. Built-ins, relative paths, #imports and package self-imports are excluded from this manifest check; TypeScript still checks their resolution. Side-effect imports are also checked when dependency checking is enabled. Missing/malformed configuration never becomes a passing result.

The declaration check accepts dependencies, devDependencies, peerDependencies and optionalDependencies as explicit declarations. It does not certify production versus development dependency placement, evaluate computed imports, prove an optional dependency is safely guarded, or audit other packages' source. A workspace paths alias may resolve source while hiding a broken published export; verify packed/installed declaration consumers separately without those aliases.

checkTypes({files:[],signal}) returns cancelled with ok:false and preserves signal.reason. The checker is synchronous: cancellation is cooperative at checkpoints, with an optional TypeScript cancellationToken for synchronous compiler callbacks; it cannot process a same-thread timer during compilation. Unexpected compiler/IO exceptions propagate instead of becoming success.

buildTypescript({...options,signal}) rejects with name:'AbortError' on cancellation and preserves reason/compiler details in cause. Its owned esbuild context is cancelled, listeners removed, and context disposed before settling; ordinary esbuild failures retain errors/warnings. Build output is not atomic: failed/cancelled builds may leave files, so callers needing promotion guarantees must use a staging directory. The default target is node20 for Node/neutral and es2022 for browser; format:'iife' is also supported. CommonJS registration validates every extension before changing hooks and returns an idempotent disposer.

Focused verification#

From this package, run npm run build then node --experimental-strip-types --test test/*.test.ts. The foundation check packs the built package and required installed dependencies, installs them offline into a disposable npm prefix, and checks declarations via public exports with no source aliases. It also compiles representative server, browser and portable packages, checks denied Node globals/nonexported subpaths, undeclared dependencies and cleanup. This requires installed dependencies, including esbuild's platform binary; all temporary files/cache are removed. It does not start applications or exercise a live browser. Archive fixtures skip prepack because the package-local build has already run; this is not a release publication check.

Source maintenance#

The source files follow the root formatting policy. Keep transpilation and execution separate when extending these entry points:

File Responsibility and boundary
src/transform.ts Text transpilation and synchronous diagnostic checks; never emits during typechecking.
src/dependencies.ts Literal-import manifest diagnostics, with invocation-local caching and no imported-code execution.
src/build.ts esbuild output and owned cancellation/disposal; callers own staging and promotion.
src/loader.ts / src/register.ts Trusted Node module loading and process-wide CommonJS hook ownership. Dispose nested registrations in reverse order.
src/tsconfig.ts Validated config generation and same-directory temporary-file cleanup; not a cross-process reservation.
src/presets.ts Fresh environment configuration data, safe to import without Node tooling.
src/validation.ts Shared input narrowing; not filesystem authorization or a compiler graph budget.

Run formatting and ESLint from the repository root with this package as the explicit scope. Run builds and the focused tests from this directory. The installed-consumer fixture checks public exports offline; it does not start an application or establish live-browser compatibility.

Public and internal function contracts use typed @param and @returns tags; public option/result fields explain defaults and ownership at their declarations. Local constants document provenance, constraints or ownership, and loop comments explain iteration bindings. The reviewed-scope ESLint gate checks missing/empty contracts as well as formatting; it does not establish runtime correctness.

Implementation sources

Implementation files for the APIs described on this page.

ZeruxJS · Open source · MIT OR Apache-2.0

Make yourself at home.

Every shortcut has a visible control too. Reading and navigation work without JavaScript.

Ctrl / ⌘ K
Search all documentation
/
Search, outside editable fields
?
This help, outside editable fields
↑ / ↓
Move through search results
Esc
Close a dialog or version menu
Progress, privacy, offline reading and controls →

Reset this learning record?

This removes course answers, exercise confirmations, bookmarks and recent pages for this docs version in this browser. Export a copy first if you want to keep it.

Search documentation

Type at least two characters.