Modules & Local Use

The Course
•
4 min read

Install Node.js 22+ and npm, extract event-gateway.zip, and open a terminal inside event-gateway. Run npm install once, then npm run check, npm start and npm test. Start prints Types and true. All data is local; no account, API key, server or network transport is needed.

Read domain.ts first, then channel.ts and gateway.ts. Index.ts deliberately exports the supported surface. Main.ts is one caller. The private package.json resolves its own name through exports, so consumer.ts can import typed-event-gateway and check the generated .d.ts boundary without uploading anything.

The build uses strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes, declaration and noEmitOnError. NodeNext resolves .js imports in TypeScript source to the corresponding .ts files, then emits .js for Node and declarations for TypeScript consumers. Keep dist and node_modules out of authored source.

If checking fails, fix the source and rebuild rather than editing dist. Public-type tests run after declaration generation, and runtime tests execute generated JavaScript. These are complementary checks: an export can disappear even when the internal implementation still works.

Predict, check, and run

Write the output before running. Use Check types first, then Check & run. Types disappear at runtime: explain both what the compiler checks and what the code actually does. Each editor is an independent ES module; await asynchronous work explicitly.

Predict, then runTypeScript
const commands = ["npm install", "npm run check", "npm start", "npm test"];

console.log(commands.join(" -> "));

Enable JavaScript to edit and type-check this example.

Check your prediction
npm install -> npm run check -> npm start -> npm test

Inspect the declaration path a public caller sees

The build has two outputs: JavaScript for execution and declarations for checking. consumer.ts imports the package name through exports, so it sees the declared public entry instead of reaching into internal source. Re-exporting an implementation and making it discoverable to a consumer are related but separate packaging steps.

A missing public export may already fail while building main.ts. Repair the source entry, rebuild, and only then interpret the separate consumer check. Generated declarations are evidence of the source build, not another implementation to maintain manually.

Boundary or caseWhat to inspect
index.tsForward supported runtime and type exports
package exportsSelect .d.ts for checking and .js for ES module execution
consumer.tsCheck valid and intentionally invalid calls without running misuse

Follow createGateway from source re-export through generated declaration to consumer import. Inspect one erased type-only import in emitted JavaScript. Never execute the negative consumer merely to observe that its invalid operations fail.

Build it yourself

Exercise

Modules & Local Use: practise

Write a readonly tuple describing the stages source, declarations and consumer. Print source -> declarations -> consumer. Then identify the actual files and commands for those stages in the download.

Your workspaceTypeScript
// Start from the stated contract. Add a valid call and an edge case.

Enable JavaScript to edit and type-check this example.

Hint 1: the idea

This small recall step prepares you to trace the real module boundary.

Hint 2: a first step

Use a readonly three-string tuple and join it with an arrow separator.

Show one solution
One possible solutionTypeScript
const stages: readonly [string, string, string] = [
  "source",
  "declarations",
  "consumer"
];

console.log(stages.join(" -> "));

Enable JavaScript to edit and type-check this example.

source -> declarations -> consumer

Trace the implementation against the task before comparing styles. A passing example supports that case; use the changes below to challenge the wider contract.

Change it and test it

Inspect dist/index.d.ts and dist/gateway.js. Identify which definitions exist only for checking. Temporarily remove one public export and run check; a source consumer such as main.ts may report it during the build before the separate consumer step. Restore it in source, then confirm both checking stages pass.

Was this article helpful?

Your response is saved on this device.