How to fix "Type X is not assignable to type Y" in TypeScript
TypeScript shows error TS2322 when assigning a value or passing a function argument:
error TS2322: Type 'string' is not assignable to type 'number'.
or
error TS2322: Type '{ name: string; }' is not assignable to type 'User'.
Property 'email' is missing in type '{ name: string; }' but required in type 'User'.
What is the right way to resolve this?
Solution
The error means the shape or type of the value you are assigning does not match what TypeScript expects. The fix depends on which side is wrong.
If the target type is too strict, widen it to accept the values you are actually passing:
// Too strict:
type Status = 'active'
// Wider:
type Status = 'active' | 'inactive' | 'pending'
If the source value is missing required fields, add them:
interface User {
name: string
email: string
}
// Broken:
const user: User = { name: 'Alice' } // missing email
// Fixed:
const user: User = { name: 'Alice', email: 'alice@example.com' }
Alternative #1
When you know the value is correct at runtime but TypeScript cannot prove it statically, use a type assertion with as. This is appropriate when the narrower type is guaranteed by external logic, like a runtime check or an API contract:
const input = document.getElementById('email') as HTMLInputElement
const value: string = input.value // TypeScript now knows it is HTMLInputElement
Avoid asserting to any (as any) because it disables all type checking for that value downstream.
Alternative #2
If you are getting the error from a third-party library that returns any or a broad type, use a type guard to narrow the type safely:
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'name' in value &&
'email' in value
)
}
const data = await fetchData()
if (isUser(data)) {
console.log(data.email) // TypeScript knows data is User here
}
Type guards are safer than assertions because they check the shape at runtime.
Alternative #3
When working with useState or generic functions, TypeScript sometimes infers a narrower type than you need. Provide an explicit generic to widen it:
// TypeScript infers useState<string>, but you want string | null
const [user, setUser] = useState<string | null>(null)
// TypeScript infers the array as never[], provide the type explicitly
const [items, setItems] = useState<string[]>([])