What Are the Most Common TypeScript Compilation Errors and How to Fix Them?

What are the most common TypeScript compilation errors and how to fix them?

TL;DR

Constraints

Quick Reference

# Error Code Message Pattern Likelihood Cause Fix
1 TS2322 Type 'X' is not assignable to type 'Y' ~25% Assigning incompatible type to variable, return type, or property Match the type: change the value, widen the target type, or use a type guard [src1, src5]
2 TS2345 Argument of type 'X' is not assignable to parameter of type 'Y' ~15% Passing wrong type to a function parameter Convert the value, fix the argument, or update the function signature [src5]
3 TS2339 Property 'X' does not exist on type 'Y' ~12% Accessing a property not declared on the type Add property to interface, use type guard, or check spelling [src5, src6]
4 TS2304 Cannot find name 'X' ~10% Undeclared variable, missing import, or missing type definition Import the symbol, install @types/ package, or declare the global [src5]
5 TS7006 Parameter 'X' implicitly has an 'any' type ~8% Function parameter lacks type annotation (with noImplicitAny) Add explicit type annotation to the parameter [src2, src4]
6 TS2532 Object is possibly 'undefined' ~7% Accessing property on possibly-null/undefined value (with strictNullChecks) Add null check, use optional chaining ?., or non-null assertion ! (with caution) [src4, src6]
7 TS2741 Property 'X' is missing in type 'Y' but required in type 'Z' ~6% Object literal missing a required property Add the missing property or mark it optional with ? in the interface [src5]
8 TS2307 Cannot find module 'X' or its corresponding type declarations ~5% Module path wrong, package not installed, or missing @types/ Install the package, install @types/X, or create a declaration file [src5]
9 TS1005 'X' expected ~4% Syntax error — missing bracket, semicolon, or keyword Check for missing }, ), ;, or mismatched template literals [src3, src6]
10 TS18048 'X' is possibly 'undefined' ~3% Variable-level undefined check (stricter variant of TS2532) Narrow the type with an if check or optional chaining [src4]

Decision Tree

START — TypeScript compilation error
├── Is it a TS2XXX error (type/semantic)?
│   ├── TS2322 / TS2345 — Type mismatch
│   │   ├── Primitive mismatch (string vs number)? → Change the value or the type annotation
│   │   ├── Object shape mismatch? → Add missing properties or use Partial<T>
│   │   ├── Union type issue? → Use a type guard to narrow the type
│   │   └── Function return type? → Fix the return statement or the declared return type
│   ├── TS2339 — Property does not exist
│   │   ├── Typo in property name? → Fix the spelling
│   │   ├── Property exists at runtime but not in type? → Extend the interface or use type assertion
│   │   └── Working with union type? → Narrow with type guard before accessing
│   ├── TS2304 — Cannot find name
│   │   ├── Missing import? → Add import statement
│   │   ├── Global (e.g., window, process)? → Install @types/node or add to global.d.ts
│   │   └── Third-party library? → Install @types/{lib} package
│   ├── TS2532 / TS18048 — Possibly undefined
│   │   ├── Optional property? → Use optional chaining: obj?.prop
│   │   ├── Array .find() result? → Add undefined check before use
│   │   └── Known to exist at runtime? → Use non-null assertion ! (last resort)
│   ├── TS2741 — Missing property
│   │   └── Object literal? → Add the property or make it optional in the interface
│   └── TS2307 — Cannot find module
│       ├── npm package? → npm install {package} && npm install -D @types/{package}
│       ├── Local file? → Check relative path and file extension
│       └── CSS/JSON/image? → Add declaration file (e.g., declarations.d.ts)
├── Is it a TS7XXX error (strict mode)?
│   ├── TS7006 — Implicit any
│   │   └── Add type annotation: (param: Type) => ...
│   └── TS7053 — Element implicitly has 'any' type (index access)
│       └── Add index signature: { [key: string]: ValueType }
├── Is it a TS1XXX error (syntax)?
│   └── TS1005 — Expected token
│       └── Check brackets, parentheses, and template literal backticks
└── DEFAULT → Read the last line of the error chain — it identifies the root cause [src1]

Step-by-Step Guide

1. Read the error message structurally

TypeScript error messages are chains. Read from the last line up — the final line identifies the root incompatibility. [src1]

Type '{ name: string; age: string; }' is not assignable to type 'User'.
  Types of property 'age' are incompatible.
    Type 'string' is not assignable to type 'number'.
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
              This is the actual cause — age should be a number.

Verify: tsc --noEmit --pretty 2>&1 | head -20 → shows formatted error with context

2. Check your tsconfig.json strict settings

Many errors only appear when strict mode is enabled. Understand what is active. [src2, src4]

{
  "compilerOptions": {
    "strict": true,           // Enables ALL of the below:
    "noImplicitAny": true,    // TS7006: no untyped params
    "strictNullChecks": true, // TS2532: null/undefined checks
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true
  }
}

Verify: tsc --showConfig | grep strict → shows effective strict settings

3. Fix TS2322 / TS2345 — type mismatches

The most common errors. Structural typing means shapes must match. [src1, src5]

// TS2322: Type 'string' is not assignable to type 'number'
let age: number = "25";        // Error
let age: number = Number("25"); // Fixed — explicit conversion

// TS2345: Argument of type 'string' is not assignable to parameter of type 'number'
function double(n: number): number { return n * 2; }
double("5");                    // Error
double(Number("5"));            // Fixed

// Object shape mismatch
interface User { name: string; age: number; }
const user: User = { name: "Alice" }; // TS2741: Property 'age' is missing
const user: User = { name: "Alice", age: 30 }; // Fixed

4. Fix TS2339 — property does not exist

Narrow the type before accessing properties on union types. [src5, src6]

// Error: Property 'email' does not exist on type 'User | Admin'
function getEmail(person: User | Admin): string {
  return person.email; // Error if only Admin has email
}

// Fixed with type guard
function getEmail(person: User | Admin): string {
  if ("email" in person) {
    return person.email; // TypeScript narrows to Admin
  }
  return "no-email";
}

5. Fix TS2532 / TS18048 — possibly undefined

Use narrowing, optional chaining, or the nullish coalescing operator. [src4, src6]

// Error: Object is possibly 'undefined'
const users: User[] = [];
const first = users.find(u => u.active);
console.log(first.name);  // TS2532

// Fixed: null check
const first = users.find(u => u.active);
if (first) {
  console.log(first.name);  // TypeScript knows first is defined here
}

// Fixed: optional chaining + fallback
console.log(first?.name ?? "unknown");

6. Fix TS2307 — cannot find module

Module resolution depends on moduleResolution in tsconfig.json. [src5]

# Missing npm package
npm install lodash
npm install -D @types/lodash
// declarations.d.ts — place in project root or src/
declare module "untyped-package";           // Minimal: types as any
declare module "*.css" {
  const content: Record<string, string>;
  export default content;
}
declare module "*.svg" {
  const src: string;
  export default src;
}

Verify: tsc --traceResolution 2>&1 | grep "untyped-package" → shows resolution path

Code Examples

TypeScript: Type guard patterns for eliminating common errors

// Input:  Values with union types that trigger TS2339/TS2532
// Output: Type-safe access patterns that eliminate compilation errors

// 1. Discriminated union — eliminates TS2339
interface Circle { kind: "circle"; radius: number; }
interface Square { kind: "square"; side: number; }
type Shape = Circle | Square;

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle": return Math.PI * shape.radius ** 2; // TS knows: Circle
    case "square": return shape.side ** 2;             // TS knows: Square
  }
}

// 2. User-defined type guard — eliminates TS2339 on unknown types
function isUser(obj: unknown): obj is User {
  return typeof obj === "object" && obj !== null
    && "name" in obj && "age" in obj;
}

// 3. Assertion function — eliminates TS2532
function assertDefined<T>(val: T | undefined, msg: string): asserts val is T {
  if (val === undefined) throw new Error(msg);
}

const item = items.find(i => i.id === targetId);
assertDefined(item, `Item ${targetId} not found`);
console.log(item.name); // No TS2532 — TypeScript knows item is defined

TypeScript: tsconfig.json strict migration strategy

// Input:  Existing JS/TS project with no strict mode
// Output: Incremental strict mode adoption without breaking the build

// tsconfig.json — Phase 1: Enable strict gradually
// {
//   "compilerOptions": {
//     "strict": false,
//     "noImplicitAny": true,        // Phase 1
//     "strictNullChecks": false,    // Phase 2
//     "strictFunctionTypes": false  // Phase 3
//   }
// }

// Phase 1: Fix all TS7006 (implicit any) errors
// Before:
function process(data) { return data.value; }
// After:
function process(data: { value: string }): string { return data.value; }

// Phase 2: Enable strictNullChecks, fix TS2532 errors
// Before:
const el = document.getElementById("app");
el.innerHTML = "Hello"; // TS2532: Object is possibly 'null'
// After:
const el = document.getElementById("app");
if (el) { el.innerHTML = "Hello"; }

// Phase 3: Enable strictFunctionTypes
// Catches unsafe contravariance in callback types

Anti-Patterns

Wrong: Silencing errors with as any

// BAD — as any hides the real type error; breaks at runtime [src6]
const data: any = fetchData();
const name: string = (data as any).user.name;
// If data.user is null, this throws at runtime — TypeScript can't help you

Correct: Use proper typing or unknown

// GOOD — type-safe with runtime check [src6]
interface ApiResponse { user: { name: string } | null; }
const data: ApiResponse = await fetchData();
const name: string = data.user?.name ?? "anonymous";
// TypeScript ensures null safety; no runtime surprise

Wrong: Using @ts-ignore instead of fixing the error

// BAD — suppresses ALL errors on the next line, including real bugs [src1]
// @ts-ignore
const result: number = "not a number" + someUndefinedVar;
// Both the type error AND the undefined variable are hidden

Correct: Use @ts-expect-error with explanation (or fix the type)

// GOOD — @ts-expect-error fails if the error disappears [src1]
// @ts-expect-error — third-party lib types are wrong, tracked in JIRA-1234
const result = thirdPartyLib.brokenMethod();

// BEST — fix the actual type
const result: number = parseInt(someValue, 10) || 0;

Wrong: Widening types to avoid errors

// BAD — making everything optional defeats type safety [src5]
interface User {
  name?: string;   // Was required, made optional to "fix" TS2741
  email?: string;  // Was required, made optional to "fix" TS2741
  age?: number;    // Was required, made optional to "fix" TS2741
}
// Now every access needs ?. and every consumer must handle undefined

Correct: Provide the required data or use Partial<T> explicitly

// GOOD — keep the interface strict; use Partial only where needed [src5]
interface User {
  name: string;
  email: string;
  age: number;
}

// For creation forms where fields are filled incrementally:
type UserDraft = Partial<User>;
// For the final validated object:
function createUser(draft: UserDraft): User {
  if (!draft.name || !draft.email || !draft.age) {
    throw new Error("All fields required");
  }
  return { name: draft.name, email: draft.email, age: draft.age };
}

Wrong: Non-null assertion (!) everywhere

// BAD — ! tells TypeScript "trust me, it's not null" — but it might be [src4]
const element = document.getElementById("app")!;
element.innerHTML = "Hello"; // Crashes if #app doesn't exist

const user = users.find(u => u.id === id)!;
user.name = "Updated"; // Crashes if user not found

Correct: Explicit null checks

// GOOD — handle the null case explicitly [src4]
const element = document.getElementById("app");
if (!element) throw new Error("Required element #app not found in DOM");
element.innerHTML = "Hello"; // TypeScript knows element is HTMLElement

const user = users.find(u => u.id === id);
if (!user) {
  console.error(`User ${id} not found`);
  return;
}
user.name = "Updated"; // TypeScript knows user is defined

Common Pitfalls

Diagnostic Commands

# Type-check without emitting (fastest error check)
npx tsc --noEmit --pretty

# Show all errors with file and line numbers
npx tsc --noEmit 2>&1 | head -50

# Count total errors
npx tsc --noEmit 2>&1 | grep "error TS" | wc -l

# Find errors of a specific code
npx tsc --noEmit 2>&1 | grep "error TS2322"

# Show effective tsconfig (see what strict flags are actually on)
npx tsc --showConfig

# Trace module resolution (debug TS2307)
npx tsc --traceResolution 2>&1 | grep "Module name"

# Watch mode — re-check on every save
npx tsc --noEmit --watch --pretty

# List all files tsc will compile
npx tsc --listFiles

# Generate declaration files to check type exports
npx tsc --declaration --emitDeclarationOnly

Version History & Compatibility

Version Status Key Error Behavior Changes
TypeScript 7.0 Beta (Apr 2026) Beta — stable in ~2 months Go-based compiler (~10× faster than 6.0); strict: true is now the default; noUncheckedSideEffectImports and stableTypeOrdering default to true; target: es5, downlevelIteration, moduleResolution: node/node10, amd/umd/systemjs/none modules, and baseUrl removed; esModuleInterop and allowSyntheticDefaultImports cannot be false; module defaults to esnext; types defaults to [] (no auto-inclusion of @types/*) [src9]
TypeScript 6.0 (Mar 2026) Final JS-based release Transition release — adds deprecations, new default-value changes, and migration flag preparing for 7.0
TypeScript 5.9 (Aug 2025) Supported import defer syntax; module: node20 mode; better tsc --init defaults (moduleDetection: force, target: esnext); MDN-sourced DOM API summaries; cached mapper instantiations; ~11% faster file-existence checks [src8]
TypeScript 5.8 (Feb 2025) Supported Stricter return type checking in conditional branches; require() of ESM in nodenext [src7]
TypeScript 5.7 (Nov 2024) Supported Improved detection of uninitialized variables; better error messages [src7]
TypeScript 5.5 (Jun 2024) Supported Inferred type predicates; better narrowing in control flow
TypeScript 5.4 (Mar 2024) Supported Narrowing in closures; NoInfer<T> utility type
TypeScript 5.0 (Mar 2023) Supported const type parameters; decorator metadata; --moduleResolution bundler
TypeScript 4.9 (Nov 2022) Maintenance satisfies operator (alternative to as for validation without widening)
TypeScript 4.0 (Aug 2020) EOL Variadic tuple types; labeled tuple elements

Decision Logic

If error code is TS2322 or TS2345 and the mismatch is between primitives (string vs number)

Convert explicitly with Number(), String(), or Boolean() at the assignment site — do not widen the target type. [src1, src5]

If error code is TS2339 ("Property X does not exist") on a union type

Add a discriminant field (kind: "circle") or a user-defined type guard (function isX(o): o is X) before property access — never use (obj as any).prop. [src5, src6]

If error code is TS2532 or TS18048 ("possibly undefined") and the value comes from Array.find(), Map.get(), or document.querySelector()

Narrow with an if check or use optional chaining ?. + nullish coalescing ??; reserve non-null assertion ! for cases where the value is guaranteed by an outer invariant. [src4, src6]

If error code is TS2307 ("Cannot find module") for a third-party JS library

Run npm install -D @types/{pkg}; if no DefinitelyTyped package exists, create declarations.d.ts with declare module "{pkg}"; and file an issue upstream. [src5]

If error code is TS7006 ("implicitly has an any type")

Add an explicit parameter type annotation; if the input is genuinely untyped (e.g., JSON parse output), type it as unknown and narrow before use — never any. [src2, src4]

If your tsconfig predates 2026 and you want to upgrade to TypeScript 7.0

Before bumping the version: remove target: es5, downlevelIteration, baseUrl, and any legacy module setting (amd/umd/systemjs/none); switch moduleResolution: node to bundler or nodenext; ensure esModuleInterop and allowSyntheticDefaultImports are not explicitly false; explicitly list every @types/* package in types (auto-inclusion is gone). [src9]

If errors only appear in VS Code but tsc passes on the CLI

Pin the workspace TS version: set "typescript.tsdk": "node_modules/typescript/lib" in .vscode/settings.json and run TypeScript: Restart TS Server. [src2]

When to Use / When Not to Use

Use When Don't Use When Use Instead
You see a TS error code in compiler output Error is a runtime exception (no TS prefix) Check browser console / Node.js stack trace
Migrating JS to TS and need to fix type errors Error is from ESLint / Prettier (not tsc) Check .eslintrc or Prettier config
Enabling strict mode on an existing project Error is in a .js file with no // @ts-check Enable allowJs + checkJs in tsconfig
Type-checking fails in CI/CD pipeline Error is only in IDE (VS Code) but tsc passes Restart TS Server: TypeScript: Restart TS Server
Third-party library has no types Error is from a build tool (Webpack, Vite) Check bundler config, not tsconfig

Important Caveats