Complete worked example
typescript
export type Role = { title: string };
export function formatRole(role: Role): string { return role.title.toUpperCase(); }- Reasoning
- The alias is erased while formatRole remains an exported JavaScript function.
Typorithm · medium
Step 1 of 4 · intro card
Choose module settings for the actual execution host instead of treating import syntax as sufficient.
A module can export runtime values, type declarations or both. Type-only imports make a dependency’s role explicit and are erased from emitted JavaScript. A normal import may remain because its runtime binding or side effects matter. Distinguishing these roles helps prevent accidental cycles.
Choose module and moduleResolution together for the host. Bundler mode describes a bundler that resolves source imports; NodeNext models Node’s package and extension rules. A configuration that type-checks for a bundler is not evidence that emitted files run directly under Node.
The worked file exports a public Role type and a runtime formatter.
The worked file exports a public Role type and a runtime formatter. A separate consumer imports Role with import type and the formatter as a value. With verbatimModuleSyntax, write the intended distinction explicitly rather than relying on the compiler to guess which imports should disappear.
In an ESM Node package, relative emitted imports commonly need .js extensions in source imports so the resulting JavaScript resolves correctly. A bundler may accept extensionless imports. Keep a package.json type setting, compiler configuration and executable smoke test alongside the chosen example.
typescript
export type Role = { title: string };
export function formatRole(role: Role): string { return role.title.toUpperCase(); }The rejected type-only import is used as a runtime value.
The rejected type-only import is used as a runtime value. An interface has no JavaScript constructor to log or instantiate. Fixing the error requires understanding whether the consumer needs a type, a real value export, or both, rather than changing import spelling randomly.
paths aliases help the compiler resolve names but do not generally rewrite emitted JavaScript imports. Configure the runtime or bundler consistently, or use supported package imports and exports. A successful editor lookup cannot substitute for running the emitted entrypoint.
typescript
type Role = { title: string };
// @ts-expect-error A type alias has no runtime value.
const constructor = Role;Create a shared Result type and an unwrap runtime function in one module, then consume them from another.
Create a shared Result type and an unwrap runtime function in one module, then consume them from another. Use explicit type-only imports for Result and a value import for unwrap. Keep the type export independent of a framework-specific runtime dependency.
Compile the two-file exercise with an explicit configuration and execute its emitted entrypoint in the intended host. Check both success and failure paths. The displayed single-file starter is the module’s implementation; split the exports and imports as the task describes.
Step 1: Export Result and unwrap. Step 2: Import the type and runtime function separately.
typescript
export type Result<T> = { ok: true; value: T } | { ok: false; reason: string };
export function unwrap<T>(result: Result<T>): T { throw new Error("TODO"); }The solution exports a tagged generic Result and an unwrap implementation that throws the failure reason.
The solution exports a tagged generic Result and an unwrap implementation that throws the failure reason. In the consumer, import type { Result } and import { unwrap } preserve the distinction between erased contracts and required runtime code.
Inspect emitted imports and run the consumer, not just the implementation file. To compare NodeNext and Bundler, use separate configurations and package metadata. Do not label an unresolved import as a typing problem if the runtime simply cannot locate the emitted file.
typescript
export type Result<T> = { ok: true; value: T } | { ok: false; reason: string };
export function unwrap<T>(result: Result<T>): T {
if (!result.ok) throw new Error(result.reason);
return result.value;
}
// Acceptance checks
if(unwrap({ok:true,value:3})!==3)throw new Error("unwrap");let failed=false;try{unwrap({ok:false,reason:"offline"})}catch{failed=true}if(!failed)throw new Error("failure");In an interview, explain type position versus value position and why class declarations occupy both spaces.
In an interview, explain type position versus value position and why class declarations occupy both spaces. Describe one import that must stay for side effects and one that must disappear because it names only an interface.
The production course returns to package exports, declarations and compiler migration. First, finish foundational class and JavaScript interoperability contracts so the shared modules contain intentional, testable public surfaces.
Optional stretch — after the core task works: Repeat the fixture under NodeNext ESM.
Choose module settings for the actual execution host instead of treating import syntax as sufficient.