TypeScript — TS2322: Type is not assignable to type
Resolve TS2322 by aligning the declared and actual types, widening narrow literals or narrowing unions correctly.
Symptoms
- error TS2322: Type 'string' is not assignable to type 'number'
- The error appears after changing a function signature
- Assigning a specific value to a union fails
- Object literals have excess or missing properties
Possible causes
- The value type does not match the declared variable or parameter type
- A string literal is inferred wider than the expected union member
- An object has properties outside the target shape or lacks required ones
- Null or undefined is not included in the target type
Diagnosis steps
Read both types in the message
npx tsc --noEmitInterpretation
The message names the source type and the target type. Comparing them shows whether the fix is widening, narrowing or adding a property.
Check the inferred literal type
npx tsc --noEmit --prettyInterpretation
Literal values sometimes widen, which changes assignability. An explicit annotation or as const can fix it.
Confirm optionality of fields
grep -n "interface\|type " src/types.tsInterpretation
A missing optional marker makes a field required, causing excess or missing property errors.
Root cause
TypeScript inferred a type for the value that is not assignable to the declared target, because of a genuine mismatch, an unexpected widening, or a shape that differs from the expected interface.
Fix
Align the value and target types by converting the value, widening or narrowing the declaration, adding missing optional markers, or making the shape match the expected type exactly.
Verify the fix
Run the type checker again and confirm the error is gone, then run tests to confirm the runtime behavior still matches.
Symptom walkthrough
The compiler reports TS2322 with the source and target types in the message. The failure can be a genuine mismatch, but it also arises from type inference: a value inferred wider than a union member, an object literal with an extra property, or a field that is required when the target marks it optional. Reading both sides of the message is usually enough to see which it is.
Fix in practice
Make the two sides agree: convert or parse the value, annotate a literal with as const or an explicit type, add optional markers to match the target, or adjust the target to include the value. Avoid casting with any, which silences the check without fixing the mismatch.
Verification
Rerun the type checker and confirm the error is gone, then run the tests to confirm runtime behavior still matches expectations. Passing types with failing behavior is not a real fix.
Diagnostic commands
Check the behavior with commands like these:
npx tsc --noEmit
npx tsc --noEmit --pretty
grep -n "interface\|type " src/types.ts