Modern JavaScript Meets Type Safety: Starting with TypeScript

VANSH KANSALVANSH KANSAL
4 min read

In modern web development, JavaScript is everywhere—from simple websites to complex enterprise applications. But while JavaScript is incredibly flexible, that flexibility comes at a cost: it’s easy to write code that fails unexpectedly at runtime.

As applications grow, this lack of safety and predictability can lead to:

  • hard-to-debug errors,

  • unclear contracts between components,

  • and a higher maintenance burden over time.

To address these challenges, many teams and developers have turned to TypeScript.

What is TypeScript?

TypeScript is a superset of JavaScript that adds static types.

Think of it as a type wrapper around JavaScript.
It doesn’t replace JS—it builds on top of it to catch errors early and make your code more predictable.

In fact, any valid JavaScript is valid TypeScript.

//This is valid JS and TS
const greeting = "Hello World!";
console.log(greeting);

But the power comes when you start adding types.


Why Do We Need TypeScript?

Here are the most common reasons teams adopt TypeScript:

Catch errors before runtime

With plain JS, you can do this without complaint:

const age = "30";
console.log(age * 2); // 60 (JavaScript coerces string to number)

But this can lead to subtle bugs. TypeScript flags these early:

const age: number = "30"; // ❌ Error: Type 'string' is not assignable to type 'number'

Better autocompletion and editor support

TypeScript makes your IDE smarter.
When you define types, you get accurate suggestions and warnings as you code.


Make large codebases easier to maintain

Types serve as living documentation.
You (or your teammates) can see what a function expects and returns without guessing.


So, What Are Types?

Types describe what shape of data a variable can hold.

Examples:

Primitive types: string, number, boolean, null, undefined

Array types: number[], string[]

let username: string = "Alice";
let age: number = 28;
let isAdmin: boolean = true;

let scores: number[] = [100, 95, 80];
let anything: any = "Could be anything";

When to use any:

  • For gradual migration from JavaScript to TypeScript

  • When working with untyped third-party libraries

  • During quick prototyping or debugging

When Don’t use any:

  • For user input or untrusted data

  • In shared interfaces or type definitions

  • As a function return type without validation

⚠ Pitfall:
any disables all type checks—mistakes like calling .toUpperCase() on non-strings won’t be caught until runtime.

Tuple types: Fixed-length arrays

let user: [string, number];
user = ["Bob", 42]; // OK
user = [42, "Bob"]; // ❌ Error

Union types: Variable can be multiple types

let id: string | number;
id = "abc123";
id = 456;

Literal types: Restrict to specific values

let role: "admin" | "user";
role = "admin"; // OK
role = "guest"; // ❌ Error

What Are Interfaces and Types?

TypeScript has two ways to define the shape of an object: type aliases and interfaces.


1.) Type Aliases

A type creates a new name for any type.

type User = {
  id: number;
  name: string;
  email?: string; // optional property
};

const user1: User = {
  id: 1,
  name: "Alice",
};

2.) Interfaces

interface is very similar but specifically for objects.

interface Product {
  id: number;
  title: string;
  price: number;
}

const item: Product = {
  id: 101,
  title: "Laptop",
  price: 999,
};

Note: Key difference:

  • interface can be extended (like inheritance):
interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

const myDog: Dog = {
  name: "Buddy",
  breed: "Golden Retriever",
};
  • type is more flexible (e.g., can define unions):
type ID = string | number;

Rule of thumb:

Use interface for object shapes you want to extend.
Use type for everything else.


Generics in TypeScript

Generics let you write reusable, type-safe code without sacrificing flexibility.

Imagine you want a function to return the first element of any array:

function getFirst(arr: any[]): any {
  return arr[0];
}

Problem: You lose type information.

With generics:

function getFirst<T>(arr: T[]): T {
  return arr[0];
}

const firstNumber = getFirst([1, 2, 3]); // Type: number
const firstString = getFirst(["a", "b", "c"]); // Type: string

✅ Generics keep the type connected through your code.


Another example: A generic interface

interface ApiResponse<T> {
  data: T;
  error?: string;
}

const response: ApiResponse<string[]> = {
  data: ["apple", "banana"],
};

TL;DR

TypeScript is more than “just a type wrapper.”
It’s a way to make your JavaScript:

  • safer

  • more predictable

  • easier to maintain

If you’re working on any serious project, consider adding TypeScript to your toolkit.

10
Subscribe to my newsletter

Read articles from VANSH KANSAL directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

VANSH KANSAL
VANSH KANSAL