Modules & Compiler Settings

The Course
•
4 min read

Use Node.js 22+ and npm. Extract the catalogue ZIP and open a terminal inside catalogue. Run npm install once, then npm run check, npm start and npm test. Start prints Types. Checking uses TypeScript 5.9.3, the same version as the browser course.

Read the imports directly: service.ts imports domain.ts; main.ts imports both service.ts and domain.ts. Domain exports runtime functions and types, service imports the decoder as a value and Book/Result as types, and main invokes the configured loader. Ordinary imports and import type have different runtime meaning, as taught on Day 1.

The compiler uses strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes and noEmitOnError. NodeNext resolves .js imports to .ts source and emits .js modules for Node. Keep generated dist and installed node_modules out of authored source.

The browser example combines the same definitions into one module because it does not resolve local project files. Do not “fix” a project import by deleting its .js extension without understanding the target environment. TypeScript configuration changes should be deliberate and checked alongside runtime execution.

Predict, run, and explain

Write the output and trace the important state changes before checking it. Then run the program. Use Check types first; execution is allowed only when the real compiler accepts the source.

Predict, then runTypeScript
const stages: readonly [string, string, string] = ["domain", "service", "main"];

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

Enable JavaScript to edit and type-check this example.

Check your prediction
domain -> service -> main

Trace commands and modules rather than directory order

The compiler checks source dependencies and emits JavaScript; Node runs the emitted main entry. Domain owns validation and state rules, service owns the injected transport adapter, and main supplies orchestration. File listing order is not an execution plan. Follow the actual imports and function calls.

Compile-only contracts deliberately contain misuse and must not run as the application. Keep their checks separate from the behavior suite, which exercises normalized data, failures and schedules through emitted code.

Boundary or caseWhat to inspect
CheckVerify source and focused negative contracts
StartRun emitted main with the deterministic transport fixture
TestCheck types and then validation, transitions and controlled schedules

Change only a transport fixture and predict valid, invalid-data and rejection results. Then inspect emitted imports: runtime decoder imports remain while type imports disappear. Recheck both checking and execution after changing module settings.

Your turn

Exercise

Modules & Compiler Settings: practise

Write a typed dependency record with domain, service and main string descriptions. Print validation, loading and orchestration respectively. Then find those responsibilities in the actual files rather than adding them all to one function.

Your workspaceTypeScript
// Use a small explicit record type and clear responsibilities.

Enable JavaScript to edit and type-check this example.

Hint 1: the idea

File boundaries should reflect behavior, not arbitrary line counts.

Hint 2: a first step

Assign one responsibility to each named stage.

Show one solution
One possible solutionTypeScript
type Responsibilities = {
  domain: string;

  service: string;

  main: string;
};

const responsibilities: Responsibilities = {
  domain: "validation",
  service: "loading",
  main: "orchestration"
};

console.log(responsibilities.domain);
console.log(responsibilities.service);
console.log(responsibilities.main);

Enable JavaScript to edit and type-check this example.

validation
loading
orchestration

Explain why the implementation meets the stated contract. Which part is enforced by the language or checker, and which part needs behavioral evidence?

Change it and test it

Run the download locally if possible and inspect the emitted service.js: its import type statements should be absent while its decoder import remains. Keep compile-only negative tests out of runtime entry points. Explain which settings make this project stricter than merely stripping type annotations.

Was this article helpful?

Your response is saved on this device.