The beginner local project introduced exports and imports. A type alias exists only during checking, so import it with import type { Book } from "./domain.js". Import runtime functions with an ordinary import such as import { decodeBook } from "./domain.js".
Type-only imports are erased from emitted JavaScript. They communicate dependency intent and avoid asking the runtime for a value that does not exist. A runtime class is different: a class can be both a constructor value and an instance type. You do not need classes for this catalogue.
The browser editors are independent single-file modules. Combine definitions in one box; do not paste relative project imports into them. Day 7’s download keeps domain.ts, service.ts and main.ts separate, with .js import extensions resolved to .ts source by the NodeNext compiler settings.
For example, domain.ts can export both type Book = { title: string } and a function label accepting Book. A caller imports label as a value and Book as a type. The self-contained equivalent below runs the same function without the file boundary.
The actual file boundary
These two listings belong in separate local files, not the single-file browser editor. The .js spelling names the emitted file Node will execute; the compiler finds domain.ts while checking.
domain.ts
export type Book = { title: string };
export function label(book: Book): string {
return book.title;
}
main.ts
import type { Book } from "./domain.js";
import { label } from "./domain.js";
const book: Book = { title: "Modules" };
console.log(label(book));
After compilation, the Book import and annotations disappear. The label import, record and console call remain. Day 7 supplies a complete configured project so you can check this locally.
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.
type Book = { title: string };
function label(book: Book): string {
return book.title;
}
const book: Book = { title: "Modules" };
console.log(label(book));Enable JavaScript to edit and type-check this example.
Check your prediction
Modules Read the compiler error
The spelling names a type, not a runtime constructor or record.
type Book = { title: string };
console.log(Book);Enable JavaScript to edit and type-check this example.
Check your diagnosis
Print a Book value instead. Type aliases are erased; they cannot be used as values.
Types disappear while runtime collaborators remain
A type alias helps check source but does not become a JavaScript constructor. A runtime function can use that alias in its contract, yet still needs a real implementation. Keeping the two roles separate prevents attempts to print or import a type as if it were a value.
The local project splits declarations into modules; the browser version combines the same definitions into one file. Do not delete necessary runtime imports merely because type imports disappear. A decoder function must still be present when emitted code calls it.
type Book = { title: string };
function label(book: Book): string {
return book.title.trim();
}
const book: Book = { title: " Types " };
console.log(label(book));
console.log(typeof label);Enable JavaScript to edit and type-check this example.
Check your prediction
Types
function Book and the annotations are erased. Label, the object and trim still exist and run. The type did not implement the normalization.
type Book = { title: string };
function label(book: Book): string {
return book.title;
}
const sameFunction = label;
console.log(sameFunction === label);
console.log(sameFunction({ title: "Modules" }));Enable JavaScript to edit and type-check this example.
Check your prediction
true
Modules An imported runtime function is still a function value, not a copied implementation generated by its parameter type. Module boundaries determine where it is supplied, while the contract checks how it is called.
Try the rule on new inputs
In the download, mark each import as type-only or runtime. Inspect emitted service.js and explain why the decoder import remains. Keep relative imports out of the single-file browser exercise.
Your turn
Modules & Type Imports: practise
Write a Book alias with title and pages, then a pageLabel function returning Title: N pages. Print Types: 120 pages. After running, describe which declarations survive into JavaScript.
// Combine the declarations here; real import/export files are in the download.Enable JavaScript to edit and type-check this example.
Hint 1: the idea
The alias disappears, but the function and record exist at runtime.
Hint 2: a first step
Use Book on the parameter and string on the return contract.
Show one solution
type Book = {
title: string;
pages: number;
};
function pageLabel(book: Book): string {
return `${book.title}: ${book.pages} pages`;
}
console.log(pageLabel({ title: "Types", pages: 120 }));Enable JavaScript to edit and type-check this example.
Types: 120 pagesExplain 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
In a local copy, export Book and pageLabel from one module and import them with the appropriate type/value forms. Run checking before execution. Explain why typeof Book cannot inspect a type alias at runtime.
Completion is saved in this browser only. It does not measure mastery.