DEV Community

Naveed Tariq
Naveed Tariq

Posted on

From JavaScript to TypeScript — Phase 1

Modern JavaScript Essentials Before Learning TypeScript

When experienced developers decide to learn TypeScript, many immediately jump into:

interfaces
generics
advanced typing

I made the same mistake.

The real problem wasn’t TypeScript — it was my JavaScript mental model.

TypeScript assumes you already write modern JavaScript.

If your JavaScript foundation is outdated, TypeScript feels unnecessarily complex.

This post documents the exact JavaScript concepts I mastered before starting TypeScript.

Why Modern JavaScript Matters
TypeScript is not a new runtime language.
It is:
JavaScript + Static Type System

TypeScript does not replace JavaScript — it analyzes it.
So before learning TypeScript, we must first write JavaScript the way TypeScript expects.

Setup (Follow Along)
Create a playground project.

mkdir js-to-ts
cd js-to-ts
npm init -y
touch index.js
node index.js
Enter fullscreen mode Exit fullscreen mode

We will evolve this file step-by-step.

  1. const and let — Understanding Mutability Older JavaScript relied heavily on var. Modern JavaScript does not.
const name = "Ali";
let age = 30;

Enter fullscreen mode Exit fullscreen mode

Why var Is Problematic

if (true) {
  var x = 10;
}
console.log(x); // 10 😬

Enter fullscreen mode Exit fullscreen mode

var ignores block scope.
Now compare:

if (true) {
  let y = 10;
}
console.log(y); // ReferenceError ✅

Enter fullscreen mode Exit fullscreen mode

Senior Developer Rule
✅ Use const by default
✅ Use let only when reassignment is required

const user = { name: "Ali" };
user.name = "Ahmed"; // allowed

user = {}; // ❌ not allowed
Enter fullscreen mode Exit fullscreen mode

👉 const protects references, not values.

Why This Matters for TypeScript
TypeScript performs better type inference when variables are stable.

const status = "active";
// inferred as literal type "active"
Enter fullscreen mode Exit fullscreen mode

Using let here would weaken the type.

Exercise
Refactor any old JS file:
remove all var
replace with const or let

  1. Arrow Functions — The Default Function Style Modern JavaScript prefers arrow functions.
const greet = (name) => `Hello ${name}`;
Enter fullscreen mode Exit fullscreen mode

Function Forms Comparison
Traditional Function

function add(a, b) {
  return a + b;
}

Enter fullscreen mode Exit fullscreen mode

Arrow Function

const add = (a, b) => a + b;
Enter fullscreen mode Exit fullscreen mode

Cleaner. Predictable. Preferred in TS projects.

The Real Reason: this
Traditional functions redefine this.

class Counter {
  count = 0;

  increment() {
    setTimeout(function () {
      console.log(this.count); // undefined 😬
    }, 1000);
  }
}

Enter fullscreen mode Exit fullscreen mode

Arrow functions capture surrounding this.

setTimeout(() => {
  console.log(this.count); // ✅
});
Enter fullscreen mode Exit fullscreen mode

Why TypeScript Cares
Many TypeScript errors originate from incorrect this binding.
Understanding arrow functions prevents hours of confusion later.

Exercise
Rewrite all callback functions using arrows.

  1. Destructuring — The Language of Modern APIs Instead of:
const user = { id: 1, name: "Ali" };

const id = user.id;
const name = user.name;
Enter fullscreen mode Exit fullscreen mode

Use destructuring:

const { id, name } = user;
Enter fullscreen mode Exit fullscreen mode

Function Parameters Destructuring

function printUser({ name, age }) {
  console.log(name, age);
}

Enter fullscreen mode Exit fullscreen mode

This pattern appears everywhere in TypeScript and React.

Arrays

const numbers = [10, 20];
const [first, second] = numbers;
Enter fullscreen mode Exit fullscreen mode

Why TypeScript Loves This
TypeScript types data shapes.
Destructuring aligns perfectly with interface-based typing.

Exercise
Take an API response object and destructure all used fields.

  1. Spread Operator — Immutability Without Pain Instead of mutation:
user.active = true;
Enter fullscreen mode Exit fullscreen mode

Prefer immutable updates:

const updatedUser = { ...user, active: true };

Enter fullscreen mode Exit fullscreen mode

Copy Arrays

const nums = [1, 2, 3];
const newNums = [...nums, 4];
Enter fullscreen mode Exit fullscreen mode

Merge Objects

const defaults = { role: "user" };
const admin = { ...defaults, role: "admin" };
Enter fullscreen mode Exit fullscreen mode

Why This Matters for TypeScript
Immutability makes types predictable.
Mutable data causes complex type narrowing issues later.

Exercise
Refactor any mutation-heavy logic using spreads.

  1. ES Modules — How Modern Code Is Organized Old JavaScript:
require("./math");
Enter fullscreen mode Exit fullscreen mode

Modern JavaScript:

// math.js
export function add(a, b) {
  return a + b;
}

// index.js
import { add } from "./math.js";


Default Export
export default function multiply() {}

import multiply from "./math.js";
Enter fullscreen mode Exit fullscreen mode

Why This Matters for TypeScript
TypeScript builds entirely on ES Modules.
If modules confuse you, TypeScript projects will too.

Exercise
Split your project into multiple files using imports/exports.

  1. Async/Await — Mandatory Before TypeScript Callbacks → Promises → Async/Await. Modern JavaScript uses async/await almost exclusively.
async function loadUser() {
  const response = await fetch(
    "https://jsonplaceholder.typicode.com/users/1"
  );
  return response.json();
}

Enter fullscreen mode Exit fullscreen mode

Usage:

loadUser().then(console.log);

Enter fullscreen mode Exit fullscreen mode

Error Handling

try {
  const user = await loadUser();
} catch (error) {
  console.error(error);
}
Enter fullscreen mode Exit fullscreen mode

Why This Matters for TypeScript
TypeScript explicitly types async results:
Promise<User>

If Promises feel unclear, TypeScript will feel overwhelming.

Exercise
Convert a .then() chain into async/await.

  1. Classes — The Bridge Into TypeScript JavaScript classes are syntactic sugar over prototypes.
class User {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return `Hello ${this.name}`;
  }
}


Inheritance
class Admin extends User {
  deleteUser() {}
}
Enter fullscreen mode Exit fullscreen mode

Why TypeScript Enhances Classes
TypeScript adds:
access modifiers
typed properties
interfaces
contracts
But the foundation is pure JavaScript.

Exercise
Create a small domain model using classes:
User
Admin
Guest

What You Can Safely Ignore
Before TypeScript, you do NOT need:
deep prototype chains
ES5 patterns
callback hell
browser internals

Phase 1 Checklist
You are ready for TypeScript if you can comfortably:
✅ use const and let correctly
✅ write arrow functions
✅ destructure objects
✅ work with modules
✅ use async/await
✅ understand classes

What Changed for Me
After mastering modern JavaScript, TypeScript stopped feeling like a new language.
It felt like JavaScript finally growing up.
Next post: Understanding the TypeScript Mental Model.

Top comments (0)