Typorithm · easy

1. Static checking and a reproducible workspace

typescriptstable-typescriptinterviewindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

1. Static checking and a reproducible workspace

0%

Concept and contract

Separate compile-time guarantees from runtime behavior; run a pinned compiler with an explicit strict configuration.

TypeScript checks a description of possible JavaScript values before execution. An annotation does not convert input, validate JSON or change arithmetic. Start with JavaScript functions and objects; use a separate empty workspace so these exercises cannot alter an application.

Pin TypeScript 7.0.2 for this track and commit the lockfile. Run npm exec tsc -- --project tsconfig.json, then execute emitted JavaScript separately. The editor and command line must use the same workspace version; otherwise identical code can appear to disagree.

Mechanism and worked example

The example makes a small contract explicit: double receives a number and returns a number.

The example makes a small contract explicit: double receives a number and returns a number. Inference computes the return type from multiplication. The emitted function contains ordinary arithmetic and no annotation, so a caller outside the checked program remains capable of violating the contract.

Use strict: true, noUncheckedIndexedAccess: true, exactOptionalPropertyTypes: true, target: ES2022, module: ESNext, moduleResolution: Bundler and types: [] for the browser-oriented single-file labs. Set noEmitOnError: true when producing executable fixtures. Later lessons explain why server modules need a different resolution mode.

Complete worked example

typescript

function double(value: number) { return value * 2; }
const result: number = double(4);
Reasoning
The number annotation restricts checked callers; multiplication remains a JavaScript runtime operation.

Counterexamples and common mistakes

The rejected call passes text where the function requires a number.

The rejected call passes text where the function requires a number. JavaScript multiplication could coerce that text, but the declared API intentionally forbids such accidental conversions. Type checking enforces the chosen contract rather than every behavior JavaScript happens to permit.

Do not hide the diagnostic with as number, any or a disabled strict option. A type assertion has no conversion effect. An expected-error directive is appropriate in a negative regression test because it fails when the anticipated diagnostic disappears; it is not a production repair.

Rejected counterexample: expected compiler diagnostic

typescript

function double(value: number) { return value * 2; }
// @ts-expect-error Text is outside this contract.
double("4");
Reasoning
The call is intentionally rejected. Keep it in the compiler test, not the executable demo.

Independent practice

Build a price formatter that accepts integer cents and returns a decimal string.

Build a price formatter that accepts integer cents and returns a decimal string. First decide how negative amounts and non-integers should behave. Make the valid-input restriction visible in documentation and enforce the integer condition at runtime; number alone includes NaN and fractions.

Start from the provided signature. Cover zero, 125 cents, a negative integer and a fractional input. Include one compile-time rejected string call in a separate test. The reader provides self-checks and records practice; run compilation and executable assertions in your own workspace.

Step 1: Check integer cents before formatting. Step 2: Format accepted cents with two decimal places.

Practice starter: solve before reading the solution

typescript

function formatCents(cents: number): string {
  throw new Error("TODO: validate integer cents, then format");
}
Reasoning
Implement validation yourself before comparing the solution. Specify fractional-input behavior.
  • Hint 1: Number.isInteger does not accept fractional cents.
  • Hint 2: Keep the negative-number policy explicit.

Solution, tests and trade-offs

The solution checks Number.isInteger before dividing by one hundred.

The solution checks Number.isInteger before dividing by one hundred. That check is a runtime business rule, while the number parameter is a static contract. Keeping both makes it possible to explain precisely which failures each layer detects instead of claiming that TypeScript validates currency.

Verify the return values and the thrown error, then inspect the generated JavaScript. Keep the runtime assertion separate from the compiler check: a successful build does not prove rounding policy, and a passing execution does not prove that invalid callers are rejected.

Practice solution and acceptance checks

typescript

function formatCents(cents: number): string {
  if (!Number.isInteger(cents)) throw new Error("Integer cents required");
  return (cents / 100).toFixed(2);
}

// Acceptance checks
if(formatCents(0)!=="0.00" || formatCents(125)!=="1.25" || formatCents(-125)!=="-1.25") throw new Error("format");
let rejected=false;try{formatCents(1.5)}catch{rejected=true}if(!rejected)throw new Error("fraction");
Reasoning
Integer validation and numeric typing solve different problems; the solution deliberately includes both.

Interview reasoning and next step

In an interview, trace input through checking, emission and execution.

In an interview, trace input through checking, emission and execution. Explain why a JavaScript consumer or network boundary can bypass the static signature. Show the specific diagnostic and the independent runtime assertion rather than saying that typed code cannot fail.

Next, study inference and literal widening. Retain this workspace configuration throughout the foundations course so a new compiler default cannot silently change the meaning of an exercise. Record a deliberate configuration change alongside the example that requires it.

Optional stretch — after the core task works: Add a separate nonnegative-price policy and compare it with signed accounting amounts.

Separate compile-time guarantees from runtime behavior; run a pinned compiler with an explicit strict configuration.