Top 10 Mistakes in TypeScript and How to Avoid Them

TypeScript is a powerful superset of JavaScript that brings static typing, better tooling, and enhanced code maintainability. However, many developers make common mistakes while working with TypeScript, leading to runtime errors, performance issues, and unnecessary complexity.

In this article, we’ll explore the Top 10 Mistakes in TypeScript and discuss best practices to avoid them with bad and good examples.

1️⃣ Ignoring Type Annotations and Letting TypeScript Infer Everything 🎯

Mistake: Relying Too Much on Type Inference

TypeScript can infer types, but sometimes it’s better to explicitly define them to avoid unexpected behavior.

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

console.log(add(5, "10")); // ❌ Output: "510" (string concatenation instead of number addition)

Issue: No explicit type annotations, leading to wrong results.

Solution: Use Explicit Type Annotations

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

console.log(add(5, 10)); // ✅ Output: 15

Best Practices:

  • Use explicit types for function parameters and return types.
  • TypeScript does infer types, but don’t over-rely on it.

2️⃣ Using the any Type Everywhere

Mistake: Overusing any to Skip Type Checking

let data: any = "Hello";
data = 42; // ❌ No error, but can cause unexpected issues later

Issue: Using any disables type safety, which defeats the purpose of TypeScript.

Solution: Use Proper Types or Generics

let data: string = "Hello"; // ✅ Now, only strings are allowed
data = 42; // ❌ Error: Type 'number' is not assignable to type 'string'

Best Practices:

  • Use specific types (string, number, boolean) instead of any.
  • Use union types (string | number) if a variable can have multiple types.

3️⃣ Not Using Interfaces or Type Aliases for Objects 🏗️

Mistake: Using Inline Object Types

function getUser(user: { name: string; age: number }) {
  console.log(`${user.name} is ${user.age} years old.`);
}

Issue: Hard to reuse and scales poorly.

Solution: Use Interfaces for Better Readability

interface User {
  name: string;
  age: number;
}

function getUser(user: User) {
  console.log(`${user.name} is ${user.age} years old.`);
}

Best Practices:

  • Use interfaces or type aliases for object shapes.
  • Helps in code reuse and maintainability.

4️⃣ Using == Instead of === for Comparisons 🔍

Mistake: Using == Leads to Unexpected Behavior

console.log(0 == "0");  // ❌ true (type coercion)
console.log(false == ""); // ❌ true (confusing behavior)

Issue: == allows type coercion, which can lead to unexpected results.

Solution: Always Use === for Type-Safe Comparisons

console.log(0 === "0");  // ✅ false
console.log(false === ""); // ✅ false

Best Practices:

  • Always use strict equality (===) to avoid unintended type coercion.

5️⃣ Not Using Union and Intersection Types

Mistake: Using any Instead of Union Types

function logId(id: any) {
  console.log(`ID: ${id}`);
}

logId(123); // ✅ Works
logId("ABC"); // ✅ Works
logId(true); // ❌ Unexpected behavior

Issue: Allows unintended types.

Solution: Use Union Types for More Control

function logId(id: string | number) {
  console.log(`ID: ${id}`);
}

logId(123);  // ✅ Works
logId("ABC"); // ✅ Works
logId(true); // ❌ Error: Argument of type 'boolean' is not assignable

Best Practices:

  • Use union types (|) when variables can be multiple types.
  • Use intersection types (&) for combining interfaces.

6️⃣ Forgetting readonly for Immutable Properties 🔒

Mistake: Modifying Object Properties Unintentionally

class User {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

const user = new User("Alice");
user.name = "Bob"; // ❌ Allowed (even if it shouldn’t change)

Issue: Some properties should not be changed after initialization.

Solution: Use readonly to Make Properties Immutable

class User {
  readonly name: string;
  constructor(name: string) {
    this.name = name;
  }
}

const user = new User("Alice");
user.name = "Bob"; // ❌ Error: Cannot assign to 'name' because it is a read-only property.

Best Practices:

  • Use readonly for immutable fields.
  • Helps prevent accidental modification.

7️⃣ Not Handling Optional and Undefined Values Properly ⚠️

Mistake: Accessing Optional Properties Without Checks

interface User {
  name: string;
  age?: number;
}

const user: User = { name: "Alice" };
console.log(user.age.toFixed(2)); // ❌ Error: 'age' is possibly undefined

Solution: Use Optional Chaining (?.)

console.log(user.age?.toFixed(2)); // ✅ No error, returns undefined if `age` is missing

Best Practices:

  • Use ?. (optional chaining) for safe property access.
  • Use ?? (nullish coalescing) to provide default values.

8️⃣ Using let Instead of const When Possible 🚀

Mistake: Using let for Variables That Never Change

let username = "Alice";
username = "Bob"; // ❌ Modifiable variable

Issue: Allows unintended reassignments.

Solution: Use const for Immutable Variables

const username = "Alice"; // ✅ Now, `username` cannot be changed

Best Practices:

  • Use const by default.
  • Use let only when reassignment is needed.

9️⃣ Using Loops Instead of Array Methods 🔄

Mistake: Using a for Loop Instead of map()

const numbers = [1, 2, 3];
const doubled = [];

for (let i = 0; i < numbers.length; i++) {
  doubled.push(numbers[i] * 2);
}
console.log(doubled); // ❌ [2, 4, 6]

Issue: Imperative code is longer and harder to read.

Solution: Use map() for Clean and Concise Code

const doubled = numbers.map(num => num * 2);
console.log(doubled); // ✅ [2, 4, 6]

Best Practices:

  • Use array methods (map, filter, reduce) instead of loops.

🔟 Not Enabling Strict Mode in tsconfig.json 🛠️

Mistake: Leaving TypeScript's Strict Mode Disabled

If strict: false, TypeScript allows loose type checking, leading to potential runtime errors.

Solution: Enable Strict Mode

Modify tsconfig.json:

{
  "compilerOptions": {
    "strict": true
  }
}

Best Practices:

  • Always enable strict mode for better type safety.

🎯 Conclusion

Avoiding these common TypeScript mistakes leads to better code maintainability, performance, and fewer bugs.

Quick Recap

✔ Always use explicit types
✔ Avoid any (use specific types)
✔ Enable strict mode
✔ Use interfaces for better code structure
✔ Use const over let when possible

Keywords

TypeScript best practices, TypeScript mistakes, TypeScript errors, JavaScript, TypeScript tutorials.

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare