Codectionary / Developer documentation / TypeScript

Build a small receipt calculator from an empty npm folder, add types, diagnose and fix an error, then run the generated JavaScript with Node.js.

What you will build

You will calculate the total for three items priced at 12.50 each and print Total: 37.50. This small terminal program keeps the focus on the TypeScript workflow: create a project, check source code, turn it into JavaScript, then run that JavaScript with Node.js.

You need a supported Node.js installation with npm. Follow the setup guide for your operating system if node --version or npm --version does not work. This tutorial uses the normal Node.js/npm workflow; it does not ask Node to execute a .ts file directly.

1. Create the project and install TypeScript

Open PowerShell on Windows or a terminal on macOS or Linux in a directory where you can make a project. mkdir creates the folder and cd enters it. npm init -y writes a starter package.json with default answers. npm install --save-dev typescript records TypeScript as a local development dependency and creates or updates package-lock.json. npx tsc --version shows which installed compiler this project will use.

Node.js will run the compiled program later. npm downloads the compiler; npm does not itself run your TypeScript source. If installation fails, check that Node and npm have version numbers and that you have network access.

Create an npm project with a local TypeScript compiler

node --version
npm --version
mkdir typescript-receipt
cd typescript-receipt
npm init -y
npm install --save-dev typescript
npx tsc --version
mkdir src

2. Configure the compiler

Run npx tsc --init inside typescript-receipt. It creates tsconfig.json. Generated defaults change between TypeScript releases, so open that file and replace its contents with the configuration below for this tutorial. Save it next to package.json.

include chooses .ts files in src. rootDir keeps the source tree rooted there; outDir puts generated JavaScript in dist. strict enables stronger type checks, and noEmitOnError prevents this compilation from writing output when it reports errors. target selects the JavaScript language level. The default package made by npm init -y has no "type": "module" field, so CommonJS is a simple matching format for this Node example. Other projects may need different module settings.

Initialise compiler settings

npx tsc --init

Save as tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "CommonJS",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "noEmitOnError": true
  },
  "include": ["src/**/*.ts"]
}

3. Write and check a basic program

In your editor, save the code below as src/receipt.ts. A .ts file can begin with familiar JavaScript: TypeScript infers that unitPrice and quantity are numbers from their values. Multiplying them gives 37.5. toFixed(2) turns that number into a two-decimal string for display, so console.log prints Total: 37.50.

Run the check command from the project root. The --project option tells tsc to use tsconfig.json and its include setting. --noEmit asks for diagnostics without creating dist. If you see no output and the command exits successfully, this version passed the type check; it does not mean the program has run.

Save as src/receipt.ts: first version

const unitPrice = 12.5;
const quantity = 3;
const total = unitPrice * quantity;

console.log(`Total: ${total.toFixed(2)}`);

Check the project without generating JavaScript

npx tsc --project tsconfig.json --noEmit

4. Add type annotations

Replace src/receipt.ts with the typed version below. The function calculates a total from a price and quantity. Each : number on a parameter tells the checker which kind of input that parameter expects; the : number after the parameter list describes the result. The two variable annotations are explicit practice, although TypeScript could infer those types from 12.5 and 3.

The return statement multiplies the inputs. The call passes both variables into the function, then toFixed(2) formats the returned number for the output message. Type annotations help the checker, but they are removed from the compiled JavaScript and do not validate data at runtime.

Save as src/receipt.ts: typed version

function calculateTotal(price: number, quantity: number): number {
  return price * quantity;
}

const unitPrice: number = 12.5;
const quantity: number = 3;
const total = calculateTotal(unitPrice, quantity);

console.log(`Total: ${total.toFixed(2)}`);

5. Find and correct a type error

Temporarily replace only the calculateTotal call with the incorrect call below. The second argument is now the string "3" rather than the number held in quantity. Run the noEmit check again. TypeScript reports TS2345 because a string cannot be passed to the quantity: number parameter. The compiler reports a problem with your source before Node runs anything.

Replace that call with the corrected version below and run the noEmit check again. It should finish without diagnostics. Do not treat an old dist/receipt.js from a previous successful build as evidence that the broken source compiled; noEmitOnError prevents new output on error but does not delete old files.

Temporarily change the call to this

calculateTotal(unitPrice, "3")

Check and observe the TS2345 diagnostic

npx tsc --project tsconfig.json --noEmit

Correct the call

calculateTotal(unitPrice, quantity)

Check the corrected source

npx tsc --project tsconfig.json --noEmit

6. Compile and run the JavaScript

Now run the compiler without --noEmit. It checks the corrected source and writes dist/receipt.js. Open that output file if you want to inspect it: the number annotations are gone, while the multiplication and console.log call remain. Run the generated .js file with Node.js; do not substitute node src/receipt.ts for this workflow.

The terminal prints Total: 37.50. The program multiplies 12.5 by 3 to get the number 37.5; toFixed(2) produces the text 37.50, which is inserted into the message. toFixed is a simple display demonstration, not a general solution for money calculations that require exact decimal arithmetic or currency rules.

Compile the project and run the emitted file

npx tsc --project tsconfig.json
node dist/receipt.js

Expected terminal output

Total: 37.50

Files you should now have

After a successful compile, the project contains the files below. TypeScript creates dist/receipt.js; you create src/receipt.ts and tsconfig.json. npm creates package.json and package-lock.json. node_modules contains installed dependencies and is usually not committed to version control.

If dist/receipt.js is missing, confirm that you saved src/receipt.ts, are in the project root and ran the compiler without --noEmit. Read any diagnostic before trying node dist/receipt.js.

Project structure after compilation

typescript-receipt/
├─ package.json
├─ package-lock.json
├─ tsconfig.json
├─ src/
│  └─ receipt.ts
├─ dist/
│  └─ receipt.js
└─ node_modules/

Practise the full cycle

Change the quantity to 4 and predict the new output before running the check, compile and Node commands again. Then try passing a string to calculateTotal once more and explain why the check fails. TypeScript helps catch this kind of mismatch before execution, but you still need runtime tests for behaviour and validation for untrusted input.

Syntax

function calculateTotal(price: number, quantity: number): number {
  return price * quantity;
}

const unitPrice: number = 12.5;
const quantity: number = 3;
const total = calculateTotal(unitPrice, quantity);

console.log(`Total: ${total.toFixed(2)}`);

Examples

The corrected receipt calculator

The final src/receipt.ts file. In a local project, type-check and compile it before running dist/receipt.js with Node.

function calculateTotal(price: number, quantity: number): number {
  return price * quantity;
}

const unitPrice: number = 12.5;
const quantity: number = 3;
const total = calculateTotal(unitPrice, quantity);

console.log(`Total: ${total.toFixed(2)}`);
  1. calculateTotal expects two numbers and returns their product. The annotations make those expectations visible to TypeScript before the program runs.
  2. unitPrice is 12.5 and quantity is 3. Passing both numbers gives a total of 37.5. Passing "3" instead triggers TS2345 during a full project check.
  3. toFixed(2) formats 37.5 as the string 37.50; the template literal adds Total: before it. The compiled JavaScript prints Total: 37.50 in Node or a compatible preview.
  4. A preview that only transpiles TypeScript does not replace npx tsc --project tsconfig.json --noEmit. Use the local checker to verify the typed call, then run the emitted JavaScript.

Best practices

  • Install the compiler in the project and use npx tsc so the recorded version is used.
  • Keep source files separate from generated JavaScript and run the output with Node.js.
  • Check types before compiling and resolve diagnostics rather than ignoring them.
  • Test runtime results as well as type-checking, especially with input from users or APIs.

Runtime & versions

Compiled to JavaScript. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

TypeScript Handbook

Specifications & further reading