TypeScript: Type 'X' is Not Assignable to Type 'Y'
TypeScript throwing type errors? Here's how to understand and fix 'Type X is not assignable to type Y' errors without using 'any'.
**Type 'string | undefined' is not assignable to type 'string'**
TypeScript's most frustrating error. Let's fix it properly.
What This Means
You're trying to put a value somewhere, but TypeScript says "nope, wrong type".
```typescript let name: string = getName(); // might return undefined // Error: Type 'string | undefined' is not assignable to type 'string' ```
Common Scenarios
**1. API Responses** ```typescript interface User { name: string; email: string; }
const user = await fetchUser(); // returns User | null const name: string = user.name; // Error: user might be null ```
**2. Array Methods** ```typescript const users: User[] = []; const firstUser: User = users[0]; // might be undefined ```
**3. Object Properties** ```typescript const config: { theme?: string } = {}; const theme: string = config.theme; // theme is optional ```
Fix #1: Type Guards
```typescript const user = await fetchUser();
if (user) { const name: string = user.name; // safe now } ```
TypeScript knows inside the if-block, user exists.
Fix #2: Non-Null Assertion (!)
```typescript const name: string = user!.name; ```
Tells TypeScript "trust me, this won't be null". Use carefully.
Only use if you're 100% sure. Otherwise, runtime error.
Fix #3: Nullish Coalescing
```typescript const name: string = user?.name ?? 'Default'; ```
Provides fallback if undefined/null.
Fix #4: Type Assertion
```typescript const name = user.name as string; ```
Forces TypeScript to treat it as string. Dangerous - use only when you know better than TypeScript.
Fix #5: Update Type Definition
```typescript // Instead of let name: string;
// Use let name: string | undefined; ```
Accepts the reality that it might be undefined.
Real Example: Form Data
I had a form with optional fields: ```typescript interface FormData { email: string; phone?: string; }
function sendData(email: string, phone: string) { // API call }
const form: FormData = getFormData(); sendData(form.email, form.phone); // Error on phone ```
**Solution 1:** Make phone optional in function ```typescript function sendData(email: string, phone?: string) { // ... } ```
**Solution 2:** Provide default ```typescript sendData(form.email, form.phone ?? ''); ```
**Solution 3:** Type guard ```typescript if (form.phone) { sendData(form.email, form.phone); } ```
The 'any' Trap
Don't do this: ```typescript const user: any = await fetchUser(); ```
You just disabled TypeScript. Defeats the purpose.
Union Types
```typescript type Status = 'pending' | 'success' | 'error';
let status: Status = 'completed'; // Error ```
TypeScript says: "completed" isn't one of the allowed values.
**Fix:** Use correct value ```typescript let status: Status = 'success'; ```
Discriminated Unions
Better error handling: ```typescript type Result<T> = | { success: true; data: T } | { success: false; error: string };
function handleResult(result: Result<User>) { if (result.success) { // TypeScript knows result.data exists here console.log(result.data.name); } else { // TypeScript knows result.error exists here console.log(result.error); } } ```
Generic Constraints
```typescript function getValue<T>(obj: T, key: string): string { return obj[key]; // Error: can't index type T } ```
**Fix with constraint:** ```typescript function getValue<T extends Record<string, string>>( obj: T, key: keyof T ): string { return obj[key]; } ```
My Rule of Thumb
1. **Type Guard** - First choice, safest 2. **Nullish Coalescing** - When you have a sensible default 3. **Non-Null Assertion** - Only if you're certain 4. **Type Assertion** - Last resort 5. **any** - Never (okay, very rarely)
Strict Mode
If you're not using strict mode: ```json { "compilerOptions": { "strict": true } } ```
Catches more errors early. Painful at first, saves you later.
Bottom Line
TypeScript errors are annoying but they prevent runtime bugs.
Don't fight TypeScript. Fix the actual type issue.
Took me months to stop using 'any' everywhere. Now my code has way fewer bugs.