How to Read TypeScript Errors Without Losing Your Mind — A Developer's Cheatsheet
You're writing code. Everything feels fine. Then suddenly your editor lights up red. You hover over the underline and TypeScript throws a wall of text at you — nested, jargon-filled, and somehow both too long and too vague to be useful.
This happens to everyone. Even experienced developers stare at TypeScript errors for five minutes before they click. The problem isn't you — it's that TypeScript errors are written for compilers, not humans. They're technically precise but emotionally brutal.
This post is your cheatsheet for decoding them. Bookmark it. Come back to it when you're stuck.
📝 Note: This post was written with the assistance of AI. The content reflects my personal learning and understanding and should not be taken as professional advice. Please do your own research and due diligence before acting on anything written here.
🧠 The mental model — every error is saying one of three things
Before you read a single error, internalize this. Every TypeScript error — no matter how long, how nested, or how confusing — is ultimately saying one of these three things:
1. "You gave me the wrong type." You passed a string where a number was expected, or an object with the wrong shape.
2. "You're missing something I need." A required property isn't there, a function argument is absent, or a return value is missing.
3. "This might not exist — handle that case." A value could be
nullorundefinedand you haven't accounted for it.
Everything else is just detail layered on top of one of those three. When you see red, ask yourself which of the three it is — you'll narrow it down faster than reading the full error.
📖 Two rules before anything else
Rule 1 — Always read the last line first
TypeScript errors are written top-down: most general at the top, most specific at the bottom. The actual problem — the thing you need to fix — is almost always the last line.
Type '{ id: number; name: string; }' is not assignable to type 'User'.
Type '{ id: number; name: string; }' is missing the following
properties from type 'User': email, createdAt
- Top line: "these two things don't match" — not useful on its own
- Last line: "you're missing email and createdAt" — that's the fix
Train your eyes to jump to the bottom first. The top line is context. The bottom line is the answer.
Rule 2 — Find the keyword
Every error contains a keyword phrase that tells you which category you're in. Once you spot the category, you know what to look for:
| Keyword phrase | Plain English |
|---|---|
is not assignable to type | Wrong type or wrong shape |
is missing the following properties | Your object is incomplete |
does not exist on type | Property not defined on this type |
is possibly null / is possibly undefined | Haven't handled the empty case |
implicitly has an 'any' type | You didn't annotate a type |
is of type 'unknown' | TypeScript has no idea what this is |
has no overlap | Comparison can never be true — logic bug |
cannot find name | Variable doesn't exist in this scope |
no overload matches this call | Wrong argument combination |
not all code paths return a value | Function might return nothing |
is not callable / is not a function | You called something that isn't a function |
has no index signature | Dynamic key access not allowed on this type |
🗂️ Every error — explained and solved
implicitly has an 'any' type
What it means: You didn't annotate a type and TypeScript couldn't figure it out. Rather than guess, it's telling you it had to fall back to any — and it doesn't want to do that silently.
// ❌ TypeScript has no idea what 'user' is
function greet(user) {
console.log(user.name);
}
// Error: Parameter 'user' implicitly has an 'any' type.
The fix: Add a type annotation:
interface User { id: number; name: string; }
// ✅ Now TypeScript knows exactly what user is
function greet(user: User) {
console.log(user.name);
}
Note: Writing user: any explicitly is different — that tells TypeScript you've made a deliberate choice. The error is specifically about implicit any — TypeScript saying "I had to guess, and I refuse to guess silently."
is of type 'unknown'
What it means: TypeScript has been given something it knows absolutely nothing about — usually in a catch block, where anything could have been thrown.
try {
// something risky
} catch (error) {
console.log(error.message); // ❌ 'error' is of type 'unknown'
}
The fix: Narrow the type before using it:
catch (error) {
// Check it's actually an Error object before accessing .message
if (error instanceof Error) {
console.log(error.message); // ✅ TypeScript now knows what it is
}
}
is possibly 'null' / is possibly 'undefined'
What it means: The value you're using could be empty and you haven't handled that case. TypeScript refuses to let you use it as if it's definitely there.
const input = document.getElementById("email"); // returns HTMLElement | null
input.value; // ❌ 'input' is possibly 'null'
Three ways to fix it:
// Option 1 — optional chaining (safest, most common)
input?.value;
// Option 2 — check first
if (input) {
input.value; // ✅ TypeScript knows it's not null inside the if block
}
// Option 3 — non-null assertion (use sparingly — you're opting out of safety)
input!.value; // You're telling TypeScript: "trust me, it's there"
cannot find name 'X'
What it means: You used a variable, function, or type that TypeScript has never seen. Either it doesn't exist, it's out of scope, or there's a typo.
console.log(userName); // ❌ Cannot find name 'userName'
The fix: Check spelling, check that the variable is declared in the right scope, and check that you've imported it if it lives in another file.
is not assignable to type
What it means: You gave TypeScript the wrong type. This is the most common error family — it shows up when the shape doesn't match, the primitive is wrong, or the return type is incorrect.
// Wrong primitive
let age: number = "thirty"; // ❌ Type 'string' is not assignable to type 'number'
// Wrong object shape
interface User { id: number; name: string; email: string; }
const user: User = { id: 1, name: "Alice" };
// ❌ Type '{ id: number; name: string; }' is not assignable to type 'User'
// Property 'email' is missing...
// Wrong return type
function getAge(): number {
return "thirty"; // ❌ Type 'string' is not assignable to type 'number'
}
The fix: Match the expected type. Read the last line of the error — it tells you exactly what's missing or mismatched.
is missing the following properties
What it means: You created an object but left out required fields. TypeScript is telling you exactly which ones.
interface User { id: number; name: string; email: string; }
const user: User = { id: 1, name: "Alice" };
// ❌ Property 'email' is missing in type '{ id: number; name: string; }'
// but required in type 'User'
Two fixes:
// Option 1 — add the missing field
const user: User = { id: 1, name: "Alice", email: "alice@example.com" }; // ✅
// Option 2 — make the field optional in the interface if it genuinely might not be there
interface User {
id: number;
name: string;
email?: string; // ? means optional
}
does not exist on type
What it means: You're trying to access a property that TypeScript has never seen on this type. Either you're looking at the wrong variable, the property has a different name, or it needs to be added to the interface.
interface User { id: number; name: string; }
const user: User = { id: 1, name: "Alice" };
console.log(user.email); // ❌ Property 'email' does not exist on type 'User'
The fix: Either add email to the User interface, or check that you're accessing the right variable.
no overload matches this call
What it means: You called a function with the wrong combination of arguments. The word "overload" means the function accepts multiple different argument patterns — and none of them match what you passed.
fetch(12345); // ❌ No overload matches this call
How to read it: Ignore "overload 1 of 2" at the top. Jump to the last line:
Argument of type 'number' is not assignable to
parameter of type 'string | URL | Request'.
You passed a number. It wanted a string, URL, or Request object. That's the fix.
argument of type X is not assignable to parameter of type Y
What it means: You passed the wrong type into a function argument. Similar to the above but without the overload complexity.
function greet(name: string) { ... }
greet(42); // ❌ Argument of type 'number' is not assignable to parameter of type 'string'
The fix: Pass the right type, or update the function signature if the function should accept both.
is not callable / is not a function
What it means: You tried to call something as a function, but TypeScript knows it isn't one.
const user = { id: 1, name: "Alice" };
user.greet(); // ❌ This expression is not callable
// Property 'greet' does not exist on type '{ id: number; name: string; }'
The fix: Check that the method exists on the type, or that you're calling the right variable.
has no index signature
What it means: You tried to access an object using a dynamic key (a variable as the key), but the type doesn't allow that.
interface User { name: string; }
const user: User = { name: "Alice" };
const key = "name";
user[key]; // ❌ Element implicitly has an 'any' type because expression
// of type 'string' can't be used to index type 'User'
Two fixes:
// Option 1 — tell TypeScript the key is a valid key of User
user[key as keyof User]; // ✅ keyof User = "name"
// Option 2 — add an index signature to the interface
interface User {
name: string;
[key: string]: any; // allows any string key
}
has no overlap
What it means: You're comparing two things that can never be equal. TypeScript is catching a logic bug before it causes a silent problem at runtime.
const status = "active";
if (status === "deleted") { // ❌ This condition will always return 'false'
... // since '"active"' and '"deleted"' have no overlap
}
The fix: Review your logic. Either the variable is more narrowly typed than you intended, or the comparison itself is wrong.
not all code paths return a value
What it means: Your function is supposed to return something, but there's a scenario where it returns nothing. TypeScript found a path through your code that exits without a return statement.
function getLabel(status: string): string {
if (status === "active") {
return "Active";
}
// ❌ What if status is "inactive" or anything else?
// Function lacks ending return statement
}
The fix: Add a default return, or make the return type include undefined:
// Option 1 — default return
function getLabel(status: string): string {
if (status === "active") return "Active";
return "Unknown"; // ✅ all paths covered
}
// Option 2 — be honest about the return type
function getLabel(status: string): string | undefined {
if (status === "active") return "Active";
// returning undefined implicitly is now fine
}
🖥️ VS Code tips that actually help
Hover before you panic
When you see red, before reading the error message — hover over the underlined thing. VS Code shows you two things:
- What TypeScript thinks the type is
- What it expected
The gap between those two things is your bug. Nine times out of ten, seeing both sides of the mismatch makes the fix obvious without reading the full error at all.
Use the Problems panel
VS Code sometimes truncates errors in the inline tooltip. The full error lives in the Problems panel — open it with View → Problems or the shortcut Ctrl+Shift+M (Windows) / Cmd+Shift+M (Mac).
Fix errors top to bottom
If you have multiple errors, fix them in order from top to bottom. Later errors are often caused by earlier ones — fixing the first error can make three others disappear on their own.
Hover over variables, not just errors
Don't wait for an error to hover. Hover over any variable while you're writing and TypeScript shows you what type it currently holds. If it looks wrong before you get an error, fix it there — prevention is faster than diagnosis.
🛠️ Tools that translate errors into plain English
Pretty TypeScript Errors (VS Code extension)
Install this immediately. It rewrites TypeScript errors with colour coding, plain language, and collapsed noise — the same error that looked like a wall of text becomes readable at a glance. It's free and it makes a real difference, especially for nested errors.
Search for "Pretty TypeScript Errors" in the VS Code Extensions panel.
ts-error-translator
A web tool at ts-error-translator.vercel.app — paste any confusing TypeScript error and it explains it in plain English. Useful when an error is genuinely cryptic and you need a second opinion.
📋 The full cheatsheet — one table
| Error | Plain English | Quick fix |
|---|---|---|
implicitly has 'any' type | Didn't annotate a type | Add : TypeName |
is of type 'unknown' | No idea what this is — usually a catch block | Use instanceof Error check |
is possibly 'null' | Might be empty | Use ?. or check first |
is possibly 'undefined' | Might be empty | Use ?. or check first |
is not assignable to type | Wrong type or wrong shape | Match the expected type |
is missing the following properties | Object is incomplete | Add missing fields or make them optional |
does not exist on type | Property not in the interface | Add it, or check the variable |
cannot find name | Variable doesn't exist here | Check scope or spelling |
no overload matches this call | Wrong argument combination | Read the last line for the actual mismatch |
argument of type X not assignable to Y | Wrong type going into a function | Pass the right type |
is not callable / is not a function | Called something that isn't a function | Check the type has this method |
has no index signature | Dynamic key access not allowed | Use keyof or add an index signature |
has no overlap | Comparison can never be true | Logic bug — revisit the condition |
not all code paths return | Function might return nothing | Add a default return |
✅ Takeaways
- Every TypeScript error is saying one of three things: wrong type, missing something, or might not exist
- Always read the last line first — that's where the actual problem lives
- Find the keyword phrase — it tells you which category you're in before you read anything else
- Hover over everything in VS Code, not just errors — catching a type mismatch before the error appears is faster than fixing it after
- Install Pretty TypeScript Errors — it makes a genuine difference to readability
- Fix errors top to bottom — later errors often disappear when earlier ones are fixed
- TypeScript errors feel harder than they are because they're written for compilers. Once you know the categories, most errors become a two-second diagnosis
The next time your editor lights up red, you won't feel a spike of dread. You'll scan for the keyword, jump to the last line, and know exactly which of the three things TypeScript is trying to tell you.

