TypeScript Introduction + Refactor
TypeScript Introduction
Day 5: Level Up to TypeScript — Safer, Smarter JavaScript 🚀
Welcome to Day 5
You've spent four days writing JavaScript. You've built variables, functions, control flow, and a fully working DOM calculator. Now it's time to level up — to the language the professional web development world has largely moved to: TypeScript.
TypeScript is used by large companies like Microsoft, Airbnb, Slack, and Stripe. It powers modern frameworks like Next.js (React), NestJS, and Angular. In the blockchain world, tools like Hardhat and Ethers.js are written in TypeScript. If you're going to build serious web or Web3 applications, TypeScript is not optional — it's expected.
The great news: TypeScript isn't a completely new language. It's JavaScript with superpowers. Almost everything you already know still applies — you're just adding one powerful new concept on top: types.
Today's Roadmap
What it is, why it exists, and how it compares to JavaScript
Install the TypeScript compiler globally with npm
Learn string, number, boolean, array, any, and union types
Annotate variables and functions, define object shapes with interfaces
Convert your Day 4 project from JavaScript to TypeScript
What is TypeScript?
TypeScript is a programming language created by Microsoft in 2012. It is a superset of JavaScript — meaning every valid JavaScript file is also a valid TypeScript file. TypeScript adds one major feature on top of static typing.
But before we explain what that means, let's understand the problem TypeScript solves.
The Problem with Plain JavaScript
JavaScript is a dynamically typed language. This means variables don't have fixed types — they can hold any kind of data, and that data can change at any time. This is flexible, but it leads to bugs that are very hard to catch.
❌ JavaScript — Bug that's hard to notice:
// no errors shown, but the result is wrong!
function add(a, b) {
return a + b;
}
let result = add("10", 5);
// You expected: 15
// You got: "105" ← Bug! String concatenation, not math!
// JavaScript did NOT warn you about this.
// You only find out when the app breaks for a user.
✅ TypeScript — Catches the bug immediately:
// TypeScript: specifies that a and b must be numbers
function add(a: number, b: number): number {
return a + b;
}
let result = add("10", 5);
// TypeScript immediately shows an error in your editor:
// ❌ Argument of type 'string' is not assignable to parameter of type 'number'
// The bug is caught BEFORE you even run the code!
JavaScript vs TypeScript: When Do You Find the Bug?
🐛 JavaScript
🛡 TypeScript
How TypeScript Works
Browsers don't understand TypeScript directly. They only understand JavaScript. So TypeScript must go through a compilation step — the TypeScript Compiler (tsc) reads your .ts files, checks for type errors, and outputs clean .js files the browser can run.
The TypeScript Workflow
script.ts
tsc
Stop!
script.js
Runs it
TypeScript in the Real World
Understanding where TypeScript is used helps you see why it matters:
Next.js (React), Angular, and Vue 3 all have first-class TypeScript support. Job listings for React developers almost always mention TypeScript.
NestJS (the most popular Node.js enterprise framework) is written entirely in TypeScript. Express also has TypeScript type definitions.
Hardhat (the leading Ethereum development framework), Ethers.js, and The Graph all use TypeScript. Solidity smart contracts are often tested and deployed with TypeScript scripts.
Microsoft, Airbnb, Slack, Dropbox, Stripe, and thousands of other companies have migrated their codebases to TypeScript for reliability and maintainability.
Installing TypeScript
TypeScript is installed using npm (Node Package Manager). You'll need Node.js installed on your computer first — if you've done any JavaScript development, you likely have it already.
Step 1: Check if Node.js is Installed
Open your terminal (Command Prompt on Windows, Terminal on Mac/Linux) and type:
node --version
npm --version
You should see version numbers like v18.17.0 and 9.6.7. If you see errors, download Node.js from nodejs.org first.
Step 2: Install TypeScript Globally
Run this command in your terminal:
npm install -g typescript
The -g flag means global — it installs TypeScript so you can use it from any folder on your computer.
This downloads the TypeScript compiler. It may take 30–60 seconds.
Step 3: Verify the Installation
tsc --version
You should see something like:
Any version number means TypeScript is installed correctly. 🎉
Step 4: Your First TypeScript File
Create a folder called typescript-practice and inside it, create a file called hello.ts:
// hello.ts
let message: string = "Hello, TypeScript!";
console.log(message);
Now compile it in your terminal (make sure you're inside the folder):
tsc hello.ts
You'll notice a new file appeared: hello.js. Open it and you'll see:
// hello.js (generated by TypeScript compiler)
var message = "Hello, TypeScript!";
console.log(message);
: string) are removed in the compiled JavaScript. Types only exist during development — they disappear at runtime. The browser never sees them.
Useful Compiler Flag: --watch Mode
Instead of typing tsc hello.ts every time you make a change, use watch mode — it automatically recompiles when you save your file:
tsc hello.ts --watch
# Now every time you save hello.ts, it auto-compiles to hello.js
Basic Types in TypeScript
TypeScript provides a set of built-in types that cover the most common kinds of data. You already know these concepts from Day 1 — TypeScript just makes them explicit and enforced.
1. string
The string type represents any text data.
// Annotating variables as string type
let firstName: string = "Alice";
let lastName: string = 'Wonderland';
let greeting: string = `Hello, ${firstName}!`;
// TypeScript prevents wrong assignment
firstName = "Bob"; // ✅ Fine — still a string
firstName = 42; // ❌ Error: Type 'number' is not assignable to type 'string'
firstName = true; // ❌ Error: Type 'boolean' is not assignable to type 'string'
Visual — Type protection in action:
2. number
The number type covers all numbers — integers, decimals, negative values.
let age: number = 25;
let price: number = 49.99;
let temperature: number = -5;
let percentage: number = 0.85;
// All valid number operations still work
let total: number = price * 1.08;
let nextAge: number = age + 1;
// TypeScript catches string being passed as number
let score: number = "100"; // ❌ Error! "100" is a string, not a number
3. boolean
The boolean type only accepts true or false.
let isLoggedIn: boolean = false;
let isStudent: boolean = true;
let hasPermission: boolean = false;
// From comparisons — these are automatically boolean
let isAdult: boolean = age >= 18; // true
let isPassing: boolean = score > 60; // depends on score
// Error cases
isLoggedIn = 1; // ❌ Error: Type 'number' is not assignable to type 'boolean'
isLoggedIn = "true"; // ❌ Error: Type 'string' is not assignable to type 'boolean'
4. Array Types
Arrays in TypeScript are typed so every item in the array must be the same type.
// Two ways to write array types:
let scores: number[] = [85, 92, 78, 95];
let names: Array = ["Alice", "Bob", "Charlie"];
// Both are equivalent — use whichever feels natural
let flags: boolean[] = [true, false, true, true];
// TypeScript prevents mixing types in an array
scores.push(88); // ✅ Fine — 88 is a number
scores.push("A+"); // ❌ Error: Argument of type 'string' is not assignable to parameter of type 'number'
5. any — The Escape Hatch (Use With Care)
Sometimes you genuinely don't know the type of something. TypeScript provides the any type, but it disables type checking — use it rarely.
// any turns off type checking — use only when necessary
let userInput: any = "hello";
userInput = 42; // OK — no error (but no protection either)
userInput = true; // Also OK — but TypeScript can't help you
// Better alternative: union types (either/or)
let flexible: string | number = "hello";
flexible = 42; // ✅ OK — it's in the union
flexible = true; // ❌ Error — boolean not in the union
any whenever possible. Using any is like turning TypeScript off — you lose all the safety benefits. A common saying among TypeScript developers: "If you're using any, you might as well use JavaScript."
Type Inference — TypeScript Is Smart
Here's something very useful: TypeScript can often figure out the type automatically from the value you assign. This is called type inference and it means you don't always need to write the type annotation explicitly.
// TypeScript infers the type from the value
let name = "Alice"; // TypeScript knows this is a string
let age = 25; // TypeScript knows this is a number
let active = true; // TypeScript knows this is a boolean
// It still protects you even without explicit annotation!
name = 42; // ❌ Error: TypeScript inferred 'string', won't allow number
age = "old"; // ❌ Error: TypeScript inferred 'number', won't allow string
• When declaring a variable without a value:
let name: string;• In function parameters (TypeScript can't infer these)
• When the inferred type is too broad and you want to be more specific
• When you want the code to be explicitly clear for other developers
Type Annotations — Adding Types to Your Code
A type annotation is the colon followed by the type name that you add after a variable, parameter, or function return value. It's the core syntax of TypeScript.
The annotation pattern:
let variableName: TypeName = value;
// ^^^^^^^^^^
// This is the type annotation
Annotating Variables
// Annotated variable declarations
let username: string = "john_doe";
let score: number = 0;
let isOnline: boolean = false;
// Declare without value (must annotate!)
let winner: string; // Will be assigned later
let totalPoints: number; // Will be assigned later
// Later in the code...
winner = "Alice"; // ✅ String — matches annotation
totalPoints = 1500; // ✅ Number — matches annotation
totalPoints = "one thousand"; // ❌ Error — must be number
Annotating DOM Elements
When selecting HTML elements with document.querySelector(), TypeScript isn't sure which specific type of element it is — it just knows it's either an Element or null (if nothing was found). You need to tell TypeScript what you expect using type assertions with the as keyword.
❌ Without type assertion (TypeScript gives errors):
// TypeScript doesn't know this is specifically an input
const num1Input = document.querySelector('#num1');
// ERROR: Property 'value' does not exist on type 'Element | null'
console.log(num1Input.value);
✅ With type assertion (tells TypeScript what type it is):
// Use 'as HTMLInputElement' to tell TypeScript it's an input element
const num1Input = document.querySelector('#num1') as HTMLInputElement;
// Now TypeScript knows about .value, .type, .placeholder, etc.
console.log(num1Input.value); // ✅ No error!
// Other common element types:
const myDiv = document.querySelector('#result') as HTMLDivElement;
const myBtn = document.querySelector('#addBtn') as HTMLButtonElement;
const myLink = document.querySelector('a') as HTMLAnchorElement;
Common HTML Element Types
Interfaces — Defining the Shape of Objects
An interface is one of the most powerful features in TypeScript. It lets you define the exact shape of an object — what properties it should have and what types those properties should be.
Think of an interface like a contract. Any object that claims to be of that interface type must have all the required properties with the correct types. If it doesn't, TypeScript raises an error.
Basic Interface Syntax
// Define an interface
interface User {
firstName: string;
lastName: string;
age: number;
isStudent: boolean;
}
// Now use it — the object must match the interface exactly
let user1: User = {
firstName: "Alice",
lastName: "Wonderland",
age: 25,
isStudent: true
}; // ✅ All properties present and correct types
// TypeScript will catch missing or wrong-typed properties:
let user2: User = {
firstName: "Bob",
lastName: "Builder",
age: "thirty" // ❌ Error: 'string' is not assignable to type 'number'
// Also missing isStudent — TypeScript will flag that too
};
Visual: Interface as a Contract
Interface: User
lastName: string
age: number
isStudent: boolean
The blueprint / contract
✅ Valid Object
lastName: "Smith"
age: 28
isStudent: false
Matches the contract
❌ Invalid Object
lastName missing
age: "thirty" ← wrong type
isStudent: true
Breaks the contract → Error!
Optional Properties
Sometimes a property might not always be present. Add a ? after the property name to mark it as optional.
interface Product {
name: string;
price: number;
description?: string; // Optional — might not be present
discount?: number; // Optional — might not be present
}
// Valid — required fields only
let item1: Product = {
name: "Laptop",
price: 999.99
}; // ✅ Fine — description and discount are optional
// Also valid — with optional fields included
let item2: Product = {
name: "Phone",
price: 499.99,
description: "Latest model",
discount: 50
}; // ✅ Also fine
Function Interfaces
Interfaces can also describe the shape of a function — its parameter types and return type. This is exactly what we'll use in the calculator refactor.
// An interface that describes a function:
// takes two numbers, returns a number
interface Operation {
(a: number, b: number): number;
}
// Now create functions that match this interface
const add: Operation = function(a, b) {
return a + b;
};
const subtract: Operation = function(a, b) {
return a - b;
};
const multiply: Operation = function(a, b) {
return a * b;
};
// TypeScript ensures every Operation function is consistent:
add(10, 5); // ✅ returns 15
subtract(10, 5); // ✅ returns 5
// Trying to use wrong types → instant error
add("10", 5); // ❌ Error: Argument of type 'string' is not assignable to type 'number'
Typing Functions — Parameters and Return Values
Functions in TypeScript can be typed in two places: the parameters (what goes in) and the return type (what comes out). Together they form a complete type signature that protects both the caller and the implementation.
Basic Function Typing
// Parameter types come after the colon
// Return type comes after the closing parenthesis
function add(a: number, b: number): number {
return a + b;
}
// ^^^^^^^^ ^^^^^^^^ ^^^^^^
// param a param b return type
function greet(name: string): string {
return `Hello, ${name}!`;
}
function isAdult(age: number): boolean {
return age >= 18;
}
// Calling them correctly
add(10, 5); // ✅ 15
greet("Alice"); // ✅ "Hello, Alice!"
isAdult(25); // ✅ true
// Calling them wrong → TypeScript errors immediately
add("ten", 5); // ❌ Error: 'string' not assignable to 'number'
greet(42); // ❌ Error: 'number' not assignable to 'string'
Anatomy of a Typed Function:
Functions That Return Nothing: void
When a function doesn't return a value (like a function that only updates the DOM), use void as the return type.
// void means "this function doesn't return a value"
function showResult(message: string, isError: boolean): void {
const resultDiv = document.querySelector('#result') as HTMLDivElement;
resultDiv.textContent = message;
resultDiv.className = isError ? 'error' : 'success';
// No return statement — returns nothing → void
}
// Also used for event handler callbacks
function handleClick(): void {
console.log("Button clicked!");
}
button.addEventListener('click', handleClick);
Optional Parameters and Default Values
// Optional parameter with ?
function greet(name: string, title?: string): string {
if (title) {
return `Hello, ${title} ${name}!`;
}
return `Hello, ${name}!`;
}
greet("Alice"); // ✅ "Hello, Alice!"
greet("Smith", "Dr"); // ✅ "Hello, Dr Smith!"
// Default parameter values
function calculateTax(price: number, rate: number = 0.08): number {
return price * rate;
}
calculateTax(100); // ✅ 8 (uses default rate of 0.08)
calculateTax(100, 0.15); // ✅ 15 (uses provided rate of 0.15)
🛠 Refactor: Converting the Calculator to TypeScript
Now we apply everything we've learned. We'll take the JavaScript calculator from Day 4 and convert it to TypeScript step by step — adding types, asserting DOM element types, creating an interface, and then compiling the result.
Step 1 → Set up a TypeScript project
Step 2 → Add types to functions
Step 3 → Type the DOM elements
Step 4 → Create an Operation interface
Step 5 → Compile TypeScript → JavaScript
Step 1: Project Setup
Open your terminal, navigate to your calculator project folder, and initialize a TypeScript config file:
cd calculator-project
tsc --init
This creates a tsconfig.json file with many options. For this project, the defaults are fine, but make sure the DOM library is included (it usually is by default). Your project folder now looks like:
📁 calculator-project/
├── 📄 index.html ← HTML (unchanged from Day 4)
├── 🎨 style.css ← CSS (unchanged from Day 4)
├── ⚡ script.js ← OLD JavaScript (we'll replace this)
├── 🔷 script.ts ← NEW TypeScript file (we'll write this)
└── ⚙️ tsconfig.json ← TypeScript configuration
Step 2: Add Types to Functions
Look at our helper functions from Day 4 and compare them before and after adding TypeScript.
Before (JavaScript):
function showResult(
message,
isError
) {
resultDiv.textContent = message;
resultDiv.className =
isError ? 'error' : 'success';
}
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
After (TypeScript):
function showResult(
message: string,
isError: boolean
): void {
resultDiv.textContent = message;
resultDiv.className =
isError ? 'error' : 'success';
}
function add(a: number, b: number): number {
return a + b;
}
function subtract(a: number, b: number): number {
return a - b;
}
Step 3: Type the DOM Elements
Before (JavaScript):
const num1Input =
document.querySelector('#num1');
const num2Input =
document.querySelector('#num2');
const addBtn =
document.querySelector('#addBtn');
const resultDiv =
document.querySelector('#result');
After (TypeScript):
const num1Input =
document.querySelector('#num1')
as HTMLInputElement;
const num2Input =
document.querySelector('#num2')
as HTMLInputElement;
const addBtn =
document.querySelector('#addBtn')
as HTMLButtonElement;
const resultDiv =
document.querySelector('#result')
as HTMLDivElement;
Step 4: Create the Operation Interface
// Define the interface for any math operation
// It takes two numbers and returns a number
interface Operation {
(a: number, b: number): number;
}
// Now use the interface to type our functions
const add: Operation = (a, b) => a + b;
const subtract: Operation = (a, b) => a - b;
const multiply: Operation = (a, b) => a * b;
const divide: Operation = (a, b) => a / b;
// A helper to run any operation generically
function calculate(op: Operation, a: number, b: number): number {
return op(a, b);
}
// Now we can call any operation the same way
calculate(add, 10, 5); // 15
calculate(multiply, 4, 7); // 28
calculate(divide, 20, 4); // 5
The
calculate() function doesn't know or care whether it's adding, subtracting, multiplying, or dividing. It just knows it receives an Operation — something that takes two numbers and returns a number. This is called abstraction and it makes code more reusable and easier to extend.
The Complete script.ts File
Here is the complete, fully-typed TypeScript version of the Day 4 calculator:
// =============================================
// JavaScript Calculator → TypeScript (Day 5)
// =============================================
// PART A: Interface Definitions
// =============================================
// Defines what any calculator operation must look like:
// a function that takes two numbers and returns a number
interface Operation {
(a: number, b: number): number;
}
// Defines what a pair of valid inputs looks like
interface CalculatorInputs {
num1: number;
num2: number;
}
// PART B: Select & Type DOM Elements
// =============================================
// 'as HTMLInputElement' tells TypeScript these are input fields
// so it knows about .value, .placeholder, .type, etc.
const num1Input = document.querySelector('#num1') as HTMLInputElement;
const num2Input = document.querySelector('#num2') as HTMLInputElement;
// 'as HTMLButtonElement' tells TypeScript these are buttons
// so it knows about .disabled, .textContent, etc.
const addBtn = document.querySelector('#addBtn') as HTMLButtonElement;
const subtractBtn = document.querySelector('#subtractBtn') as HTMLButtonElement;
const multiplyBtn = document.querySelector('#multiplyBtn') as HTMLButtonElement;
const divideBtn = document.querySelector('#divideBtn') as HTMLButtonElement;
// 'as HTMLDivElement' tells TypeScript this is a div
// so it knows about .textContent, .innerHTML, .className, etc.
const resultDiv = document.querySelector('#result') as HTMLDivElement;
// PART C: Operation Functions (using the interface)
// =============================================
// Each of these matches the Operation interface:
// takes two numbers (a, b) and returns a number
const add: Operation = (a, b): number => a + b;
const subtract: Operation = (a, b): number => a - b;
const multiply: Operation = (a, b): number => a * b;
const divide: Operation = (a, b): number => a / b;
// PART D: Helper Functions (with full type signatures)
// =============================================
// Shows a result on the page
// message is a string, isError is a boolean, returns nothing (void)
function showResult(message: string, isError: boolean): void {
resultDiv.textContent = message;
resultDiv.className = isError ? 'error' : 'success';
}
// Reads and validates the input fields
// Returns a CalculatorInputs object, or null if inputs are invalid
function getInputs(): CalculatorInputs | null {
// .value is always a string, so we convert with Number()
const val1: string = num1Input.value;
const val2: string = num2Input.value;
// Check for empty fields
if (val1 === '' || val2 === '') {
showResult('⚠️ Please fill in both number fields!', true);
return null;
}
const num1: number = Number(val1);
const num2: number = Number(val2);
// Check for invalid (non-numeric) input
if (isNaN(num1) || isNaN(num2)) {
showResult('⚠️ Please enter valid numbers!', true);
return null;
}
// Return a typed CalculatorInputs object
return { num1, num2 };
}
// Performs a calculation using any Operation function
// op is an Operation (takes two numbers, returns number)
// symbol is the display symbol like "+", "-", etc.
function performCalculation(
op: Operation,
symbol: string,
checkDivision: boolean = false
): void {
// Get and validate inputs
const inputs: CalculatorInputs | null = getInputs();
if (inputs === null) return;
const { num1, num2 } = inputs;
// Special check for division by zero
if (checkDivision && num2 === 0) {
showResult('⚠️ Cannot divide by zero!', true);
return;
}
// Perform the calculation
const rawResult: number = op(num1, num2);
// Round to 4 decimal places to avoid floating-point messiness
const result: number = Math.round(rawResult * 10000) / 10000;
// Display the result
showResult(`${num1} ${symbol} ${num2} = ${result}`, false);
}
// PART E: Event Listeners
// =============================================
addBtn.addEventListener('click', (): void => {
performCalculation(add, '+');
});
subtractBtn.addEventListener('click', (): void => {
performCalculation(subtract, '-');
});
multiplyBtn.addEventListener('click', (): void => {
performCalculation(multiply, '×');
});
divideBtn.addEventListener('click', (): void => {
performCalculation(divide, '÷', true); // true = check for divide by zero
});
Step 5: Compile TypeScript to JavaScript
Once your script.ts file is ready, compile it:
One-time compile:
tsc script.ts
Watch mode (auto-recompile on save — recommended):
tsc script.ts --watch
If your folder has tsconfig.json, just run:
tsc --watch
After compiling, TypeScript generates a script.js file. Your index.html still links to script.js — the browser loads the compiled output, not the TypeScript source. Everything works exactly as before, but you now have full type safety during development.
Side-by-Side: TypeScript Source vs Compiled JavaScript
🔷 script.ts (you write)
interface Operation {
(a: number, b: number): number;
}
const add: Operation =
(a, b): number => a + b;
function showResult(
message: string,
isError: boolean
): void {
resultDiv.textContent = message;
}
⚡ script.js (compiled)
// (interface removed — runtime only)
const add =
(a, b) => a + b;
function showResult(
message,
isError
) {
resultDiv.textContent = message;
}
The type annotations are completely stripped during compilation. The JavaScript output is clean and browser-ready.
Exercises: Practice TypeScript
Solidify your TypeScript knowledge with these progressive exercises. Start from scratch in a new practice.ts file.
Exercise 1: Type Some Variables
Task: Annotate these variables with the correct types, then intentionally create a type error to see what TypeScript shows you.
// Add the correct type annotation to each variable
let productName = "Wireless Keyboard"; // Add ': ___' here
let productPrice = 79.99; // Add ': ___' here
let inStock = true; // Add ': ___' here
let quantity = 50; // Add ': ___' here
let categories = ["tech", "office"]; // Add ': ___' here
// Now try assigning the wrong type to one of them:
// productName = 100; // Uncomment this — what error do you see?
// inStock = "yes"; // Uncomment this — what error do you see?
Exercise 2: Type a Function
Task: Add type annotations to this function and fix any type errors.
// Add types to parameters and return value
function calculateTotal(price, quantity, taxRate) {
let subtotal = price * quantity;
let tax = subtotal * taxRate;
return subtotal + tax;
}
// This should work:
let total = calculateTotal(29.99, 3, 0.08);
console.log("Total:", total);
// This should cause a TypeScript error once you add types:
// let wrong = calculateTotal("free", 3, 0.08);
Solution:
function calculateTotal(
price: number,
quantity: number,
taxRate: number
): number {
let subtotal: number = price * quantity;
let tax: number = subtotal * taxRate;
return subtotal + tax;
}
Exercise 3: Write an Interface
Task: Define an interface for a blog post and create two objects that match it.
// Create an interface called BlogPost with these fields:
// - title: string (required)
// - content: string (required)
// - author: string (required)
// - likes: number (required)
// - isPublished: boolean (required)
// - tags: string[] (required — array of strings)
// - coverImage: string (optional)
// Your interface here:
interface BlogPost {
// ... fill this in
}
// Then create two blog posts using your interface:
let post1: BlogPost = {
// ... fill this in
};
let post2: BlogPost = {
// ... fill this in (include the optional coverImage)
};
Exercise 4: Extend the Calculator
Task: Add a "Power" button to the TypeScript calculator. It should raise num1 to the power of num2 (e.g. 2^8 = 256). Use the Operation interface and type everything correctly.
// Hint: Math.pow(a, b) raises a to the power of b
// Or use the ** operator: a ** b
// 1. Create a power operation that matches the Operation interface
const power: Operation = (a, b): number => {
// Your code here
};
// 2. Add a button in index.html:
//
// 3. Select and type the button in script.ts
const powerBtn = document.querySelector('#powerBtn') as HTMLButtonElement;
// 4. Add the event listener
powerBtn.addEventListener('click', (): void => {
performCalculation(power, '^');
});
Exercise 5: Type a Calculation History Feature
Task: Create a typed history system that stores the last 5 calculations as objects with a specific shape.
// Define a HistoryEntry interface
interface HistoryEntry {
expression: string; // e.g. "10 + 5 = 15"
result: number;
timestamp: string; // e.g. "3:45 PM"
}
// Typed history array — must only contain HistoryEntry objects
let history: HistoryEntry[] = [];
// Function to add to history
function addToHistory(expression: string, result: number): void {
const now: Date = new Date();
const timestamp: string = now.toLocaleTimeString();
const entry: HistoryEntry = {
expression,
result,
timestamp
};
history.unshift(entry); // Add to front
if (history.length > 5) {
history.pop(); // Remove oldest if more than 5
}
console.log("History:", history);
}
// Test it:
addToHistory("10 + 5 = 15", 15);
addToHistory("100 × 0.08 = 8", 8);
addToHistory("25 - 7 = 18", 18);
TypeScript Quick Reference Card
// ===== VARIABLES =====
let name: string = "Alice";
let age: number = 25;
let isActive: boolean = true;
let scores: number[] = [85, 92, 78];
// ===== FUNCTIONS =====
function greet(name: string): string {
return `Hello, ${name}!`;
}
function log(message: string): void {
console.log(message);
}
function maybe(value?: string): string {
return value ?? "default";
}
// ===== INTERFACES =====
interface User {
name: string;
age: number;
email?: string; // optional
}
interface Operation {
(a: number, b: number): number;
}
// ===== DOM ELEMENTS =====
const input = document.querySelector('#id') as HTMLInputElement;
const button = document.querySelector('#id') as HTMLButtonElement;
const div = document.querySelector('#id') as HTMLDivElement;
// ===== UNION TYPES =====
let value: string | number = "hello";
value = 42; // also OK
// ===== TYPE INFERENCE (automatic) =====
let x = "hello"; // TypeScript infers: string
let y = 42; // TypeScript infers: number
// ===== COMPILING =====
// tsc filename.ts (compile once)
// tsc filename.ts --watch (auto-compile on save)
// tsc --watch (with tsconfig.json)
Day 5 Completion Checklist
Complete this lesson
Mark as complete to track your progress