# TypeScript: “Type 'X' is not assignable to type 'Y'” (TS2322)

> TS2322: Type is not assignable to type. Read the last line of the error, handle null and undefined, widen or narrow the type, and avoid unsafe as casts.

Canonical: https://app369.com/fix/typescript-type-is-not-assignable-to-type/
Last updated: 2026-11-08

The compiler stops with Type 'string | undefined' is not assignable to type 'string' (or Type 'string' is not assignable to type '"small" | "large"', or a long nested message about objects). A value of one type is being put where TypeScript expects another, and it cannot prove the two are compatible.

**Short answer**

Read the error from the bottom: the last indented line names the exact property or value that does not fit. If the mismatch is undefined or null, handle that case first (a check, a default with ??, or an optional type). If a string should be one of a few values, type it as that union from the start, or add as const to the literal. If an object is missing a property, add it or make the target property optional. Use an as cast only when you know something TypeScript cannot, because a wrong cast hides a real bug.

## **Why the types don’t match, and the fix**

1. 01 ### **The value can be undefined or null** With strict mode on, string | undefined does not fit into string. Values from optional props, find(), Map.get(), process.env and form fields are often like this. Check for the missing case, give a default, or let the target accept undefined.```
const user = users.find((u) => u.id === id);
if (!user) throw new Error(\`No user ${id}\`);
setName(user.name); // user is User here

const port: string = process.env.PORT ?? '3000';
```
2. 02 ### **An object is missing a property, or has the wrong shape**
  > “The basic rule for TypeScript’s structural type system is that x is compatible with y if y has at least the same members as x.” [**TypeScript, Type compatibility**](https://www.typescriptlang.org/docs/handbook/type-compatibility.html) TypeScript compares objects by their properties, not by their names. An object fits a type when it has at least the properties that type requires, with compatible types. The nested lines of the error point to the property that differs.```
interface Props { title: string; count: number }

// error: property count is missing
// <Card title="Inbox" />
<Card title="Inbox" count={unread.length} />
```
3. 03 ### **A string where a union of literals is expected** let size = 'small' is typed as string, which can hold any text, so it does not fit a prop typed 'small' | 'large'. Type the variable with the union, or use const or as const so TypeScript keeps the literal value.```
type Size = 'small' | 'large';
let size: Size = 'small';

const options = { size: 'small' } as const;
<Button size={options.size} />
```
4. 04 ### **Using as to force it**
  > “TypeScript only allows type assertions which convert to a more specific or less specific version of a type.” [**TypeScript, Everyday types: type assertions**](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) An as cast tells TypeScript to trust you, and it only allows casts between related types. If you need as unknown as Something to make the error go away, the types really do not match: fix the data or the type instead.```
const canvas = document.getElementById('chart') as HTMLCanvasElement; // fine when you know the element

// a warning sign:
const user = response as unknown as User;
```

Checked against the vendor’s docs on November 8, 2026: [TypeScript Handbook: Type compatibility](https://www.typescriptlang.org/docs/handbook/type-compatibility.html); [TypeScript Handbook: Everyday types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**TypeScript “Property does not exist on type”**](https://app369.com/fix/typescript-property-does-not-exist-on-type/) · [**TypeScript “Cannot find name”**](https://app369.com/fix/typescript-cannot-find-name/) · [**“Cannot read properties of undefined”**](https://app369.com/fix/cannot-read-properties-of-undefined/)

Questions

## **More on this error**

<details>

<summary>**Should I turn off strict mode to get rid of these errors? **+</summary>

No. Strict mode is what catches the undefined and null cases that crash at runtime. Fix the few places it flags; turning it off hides them all.

</details>

<details>

<summary>**The error message is 20 lines long. Where do I look? **+</summary>

At the last indented line. TypeScript prints the outer types first and the exact property that does not fit last.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)