All posts
typescripttypes

Fixing "Type X is not assignable to type Y" in TypeScript

Understanding why TypeScript's Type X is not assignable to type Y error happens, and how to actually fix it rather than suppress it.

SR

Suhail Roushan

August 6, 2026

·
5 min read
·
0 views

Type 'X' is not assignable to type 'Y' is TypeScript's single most common error, and it's also the one developers most often suppress with as any rather than fix — which defeats the entire purpose of using TypeScript in the first place, since the error is almost always pointing at a real mismatch worth resolving.

This error means you're trying to use a value where TypeScript's structural type checking has determined the value's type doesn't satisfy the shape or constraints of the expected type — sometimes because of a genuine bug, sometimes because the types themselves need to be adjusted to accurately reflect what your code actually does.

Why This Error Happens

TypeScript uses structural typing — a value is assignable to a type if it has all the properties that type requires, with compatible types for each. When you get this error, it means somewhere in that structural comparison, a required property is missing, has an incompatible type, or the value's type is broader (or narrower) than what's expected — TypeScript is not being pedantic, it caught a real interface mismatch.

Reproducing the Error

A typical version of this error:

interface User {
  id: string;
  email: string;
  role: "admin" | "member";
}

function greetUser(user: User) {
  console.log(`Hello, ${user.email}`);
}

const apiResponse = { id: "1", email: "user@example.com", role: "editor" };
greetUser(apiResponse);
// Error: Argument of type '{ id: string; email: string; role: string; }'
// is not assignable to parameter of type 'User'.
// Types of property 'role' are incompatible.
// Type 'string' is not assignable to type '"admin" | "member"'.

The object's role property is inferred as the general string, not the literal union "admin" | "member", so it doesn't satisfy User's narrower type.

Core Concepts Behind This Error

Structural typing means shape matters, not the name of the type — two differently-named types with identical structure are interchangeable, and a type missing even one required property (or having an incompatible type for one) fails assignability, regardless of how similar the types otherwise look.

Literal types are narrower than their general primitive counterparts — a string is not assignable to a specific string literal union like "admin" | "member" because not every possible string is a valid member of that union; you need as const or an explicit type annotation to narrow it at the value's source.

Excess property checks apply specifically to object literals assigned directly, not to variables of a wider type assigned afterward — this is why the exact same "excess property" issue can appear or disappear depending on whether you construct an object inline or assign it to a variable first.

Function parameter and return type variance follows specific rules (bivariance for methods, contravariance in stricter settings) — a function type mismatch error often comes down to a parameter or return type being incompatible in a specific direction, not simply "different," which matters for understanding callback and higher-order function type errors specifically.

Fixing "Type X Is Not Assignable to Type Y"

Fix 1: Narrow literal types explicitly at their source rather than fighting inferred general types downstream:

const apiResponse = { id: "1", email: "user@example.com", role: "editor" as const };
// Or better: validate and type the API response properly with a schema library

Fix 2: Fix the actual data mismatch rather than casting it away. If role can genuinely be "editor", widen the User type to include it — the error is telling you your type definition doesn't match reality:

interface User {
  id: string;
  email: string;
  role: "admin" | "member" | "editor";
}

Fix 3: Validate external data (API responses, form input) with a runtime schema library (Zod, Valibot) rather than asserting types with as, since as only silences the type checker without verifying the value actually matches at runtime — this is the source of most "assignable" errors involving external data specifically.

Should You Ever Use as any to Fix This Error?

Almost never — as any doesn't fix the underlying mismatch, it just tells TypeScript to stop checking that value entirely, which can let real bugs through silently later in your code. Reach for as any only as a genuinely temporary, clearly-marked escape hatch while migrating code, and prefer a more targeted fix (correcting the type definition, using as const, or validating with a schema library) in virtually every other case.

Preventing This Error in Production

Type external data (API responses, environment variables, form submissions) through runtime validation rather than type assertions, since assertions don't protect you from data that doesn't actually match at runtime. Keep type definitions synchronized with what your code and data actually represent, treating a persistent assignability error as a signal to fix the type definition, not just the immediate call site.

If you hit this error, resist reaching for as or any first — read what the error says is actually mismatched, since it's almost always pointing at a real, fixable discrepancy between your code and your types.

Related posts

Written by Suhail Roushan — Full-stack developer. More posts on AI, Next.js, and building products at suhailroushan.com/blog.

Get in touch