TypeScript errors
Status: 🟩 COMPLETE Last updated: 2026-06-21 Plain-English tagline: The TypeScript error messages that look intimidating but mean small things. Decode the wall-of-text; find the fix.
What this is
A lookup reference for TypeScript errors that come up in npm run build, in tsc --noEmit, or as red squiggles in VS Code. TypeScript’s error messages are notoriously verbose; this entry decodes the common patterns.
For broader build issues that include TS errors as one cause, see Build errors 🟩.
How to read a TypeScript error
A typical error has three layers:
Type '{ name: string; }' is not assignable to type 'User'.
Property 'email' is missing in type '{ name: string; }' but required in type 'User'.
Read bottom-up: the last line is usually the actual problem (“you forgot the email field”). The first line is “TypeScript’s high-level complaint.” Long errors with nested types can stretch across 20 lines — almost always the actionable bit is at the end.
”Property ‘X’ does not exist on type ‘Y’”
What it means: You accessed .X on a value typed as Y, but Y doesn’t declare X.
Common causes:
- Typo —
user.emialinstead ofuser.email. - Type doesn’t include the property you expect — the type says
{ name: string }but you assumedemailwas there too. - API response shape changed — the runtime gives you
{ name, email }but the type says only{ name }. - Using a generic that’s too narrow —
Array<string>doesn’t have your custom method.
Fix:
- For typos: fix the spelling.
- For “the type is wrong”: update the type definition to include the property. Don’t lie about the runtime.
- For union types: narrow first.
if ("email" in user) { user.email }.
// BEFORE
function greet(user: { name: string }) {
return `Hi ${user.email}`; // ❌ Property 'email' does not exist
}
// AFTER
function greet(user: { name: string; email: string }) {
return `Hi ${user.email}`; // ✅
}”Type ‘X’ is not assignable to type ‘Y’”
What it means: You tried to assign (or pass) a value of type X somewhere expecting Y. They’re incompatible.
Common patterns:
- String vs number — passing
"42"where anumberis expected. Convert:Number("42")orparseInt("42", 10). - Optional vs required —
string | undefinednot assignable tostring. Narrow with a guard:if (x) { ... x ... }. - Subset vs superset — you have
{ name }, the function wants{ name, email }. Add the missing field. - Wider type going to narrower —
unknownnot assignable tostring. Narrow withtypeoforas.
Fix: match the types. Don’t reach for as Y (type assertion) as a first move — it silences the compiler but can crash at runtime.
”Argument of type ‘X’ is not assignable to parameter of type ‘Y’”
What it means: Same as the assignment error, but specifically when calling a function.
Common cause for objects: TypeScript’s excess-property checks. Passing { name, extraField } to a function expecting { name }:
- Object literal: errors (TypeScript catches the typo).
- Pre-existing variable: doesn’t error (TypeScript allows wider types in pre-bound vars).
function setUser(u: { name: string }) {}
setUser({ name: "George", typo: 1 }); // ❌ object literal excess property
const u = { name: "George", typo: 1 };
setUser(u); // ✅ no error (wider type via variable)Fix: when the error fires on an object literal, you usually mis-typed a field. Read carefully.
”Object is possibly ‘null’” / “Object is possibly ‘undefined’”
What it means: TypeScript thinks the value could be null/undefined, and you’re using it without a guard.
Fix paths:
- Optional chaining:
obj?.X— returnsundefinedinstead of throwing. - Nullish coalescing:
obj ?? defaultValue. - Type guard:
if (obj !== null) { ... }orif (obj) { ... }. - Non-null assertion (use sparingly):
obj!.Xsays “trust me, it’s not null."
function process(user: User | null) {
return user?.name ?? "anonymous"; // safe
// vs
return user!.name; // crashes if user is null
}"This expression is not callable” / “X is not a function”
What it means: You tried to call something that’s not a function (or whose type doesn’t say it’s a function).
Common causes:
- The variable was declared with a different type and you forgot.
- You imported the default vs a named export incorrectly (
import x from "y"vsimport { x } from "y"). - The function is conditionally undefined.
Fix: check the import / the type declaration.
”No overload matches this call”
What it means: You’re calling a function with overloaded signatures, and the arguments you passed don’t match any of them.
TypeScript’s listing of each overload is helpful — read them. The first overload that fails tells you what shape was expected.
Common in React with event handlers:
// ❌ "No overload matches this call" — event handler signature wrong
<input onChange={(value: string) => setName(value)} />
// ✅ — event handler gets ChangeEvent
<input onChange={(e) => setName(e.target.value)} />“Generic type ‘X’ requires N type argument(s)”
What it means: You used a generic like Array<> or Map<> without filling in its parameters.
Fix:
const items: Array = []; // ❌
const items: Array<string> = []; // ✅
const cache: Map = new Map(); // ❌
const cache: Map<string, User> = new Map(); // ✅“Type ‘X’ is missing the following properties from type ‘Y’: a, b, c”
What it means: You’re trying to use X as Y, but Y requires additional fields that X doesn’t have.
Fix: add the missing fields, or change the function/type to accept the narrower input.
If many of Y’s fields are optional in your use case, consider Partial<Y> or Pick<Y, "needed-fields">:
type User = { id: string; name: string; email: string; phone: string; };
function logUser(u: Pick<User, "id" | "name">) { /* ... */ }
// Now you can call with just id + name
logUser({ id: "1", name: "George" }); // ✅“‘X’ has no exported member ‘Y’”
What it means: You’re importing something from a module that doesn’t export it.
Common causes:
- Typo in the named import.
- Library version mismatch — older API uses a different name.
- Default vs named confusion —
import Foo from "x"vsimport { Foo } from "x". - The export was removed in a major version bump.
Fix: open the module’s index.d.ts (in node_modules/<package>/) or its docs. The actual exports list is there.
”Cannot find module ‘X’ or its corresponding type declarations”
What it means: The package is installed (or you’re using a custom path), but no type declarations exist.
Fix:
- For npm packages:
npm install -D @types/X. - Modern packages ship their own types — if
@types/Xdoesn’t exist, the package probably types itself. Checkpackage.json→"types". - For internal modules with no types: create
X.d.tswithdeclare module "X";(a quick stub).
”Property ‘X’ has no initializer and is not definitely assigned in the constructor”
What it means: With strict: true, class properties must be initialized.
Fix:
// ❌
class User {
name: string;
}
// ✅ Option 1: initialize
class User {
name: string = "";
}
// ✅ Option 2: definite assignment assertion
class User {
name!: string; // "I promise this gets set elsewhere"
}
// ✅ Option 3: mark optional
class User {
name?: string;
}“Element implicitly has an ‘any’ type because index expression is not of type ‘number’”
What it means: You’re indexing into a type with a key TypeScript can’t verify.
Common pattern:
const colors = { red: "#f00", green: "#0f0", blue: "#00f" };
function getColor(name: string) {
return colors[name]; // ❌ TS doesn't know `name` is a valid key
}Fix:
- Constrain the parameter:
function getColor(name: keyof typeof colors). - Type the object with an index signature:
const colors: Record<string, string> = { ... }. - Cast at access:
colors[name as keyof typeof colors](last resort).
”Type instantiation is excessively deep and possibly infinite”
What it means: A type definition is recursive in a way TypeScript can’t resolve.
Common in advanced generic code. Most app code doesn’t hit this.
Fix: simplify the type. Break recursion with explicit base cases. If the type comes from a library, file an issue or pin to a working version.
”Cannot redeclare block-scoped variable ‘X’”
What it means: You declared the same variable name twice in the same scope. Usually means the file is being treated as a script (global scope), not a module.
Fix: ensure the file has at least one import or export. If it has neither and is meant to be a module, add export {}; at the end.
”’X’ refers to a value, but is being used as a type here”
What it means: You used a runtime value where TypeScript expected a type.
Fix: use typeof X to convert a value to its type:
const config = { theme: "dark", count: 5 };
function setConfig(c: config) {} // ❌ 'config' is a value
function setConfig(c: typeof config) {} // ✅“Subsequent property declarations must have the same type” (interface merging)
What it means: Two interface declarations of the same name don’t agree on a property’s type.
Common cause: library augmentation. You added a type for Window.foo somewhere, and the same property was already declared elsewhere with a different type.
Fix: unify the types, or scope the augmentation to a narrow declare global { ... } block.
See also
- Common errors — index 🟩
- Build errors 🟩
- Supabase errors 🟩 🟦
- Browser errors 🟩
- TypeScript 🟩 — the textbook
- TypeScript — common gotchas 🟩
- Type checking 🟩