This error occurs when attempting to assign a value to an intersection type that doesn't satisfy all constituent types simultaneously. TypeScript requires values to conform to every type in the intersection, which can create impossible constraints.
This error appears when you try to assign a value to a variable typed as an intersection (Y & Z), but the value doesn't satisfy the requirements of both Y and Z at the same time. Intersection types combine multiple types using the & operator, creating a type that must have all properties and characteristics from all constituent types. Unlike union types (Y | Z) which allow values matching any of the types, intersections demand conformance to all types. When types in an intersection have conflicting requirements—such as a property being both string and number—the intersection becomes an impossible type (never), and nothing can be assigned to it. This is TypeScript's way of catching logical inconsistencies in your type definitions.
Examine the error message to understand which types are incompatible. Look for the specific properties or constraints that cannot be satisfied simultaneously.
// Error: Type 'string' is not assignable to type 'string & number'
type Impossible = { id: string } & { id: number };
const obj: Impossible = { id: "123" }; // ❌ Cannot satisfy both string AND number
// The issue: property 'id' cannot be both string and numberCheck if your intersection creates a logically impossible type. If a property appears in multiple types with different signatures, the intersection will be never.
If you want a value that can be one type OR another, use a union (|) instead of an intersection (&).
// ❌ Wrong: Intersection requires both types
type BadConfig = { mode: "dev" } & { mode: "prod" };
// ✅ Correct: Union allows either type
type GoodConfig = { mode: "dev" } | { mode: "prod" };
const config: GoodConfig = { mode: "dev" }; // Works!Intersections are for combining types that add properties, not for choosing between alternatives.
When using legitimate intersections, make sure your value has all required properties from every type.
type HasName = { name: string };
type HasAge = { age: number };
type Person = HasName & HasAge;
// ❌ Missing 'age' property
const incomplete: Person = { name: "Alice" };
// ✅ Satisfies both types
const complete: Person = { name: "Alice", age: 30 };Add all properties required by the intersection, or restructure your types if the requirements conflict.
Destructuring can cause values to lose their connection to the original intersection type, leading to unexpected type narrowing.
type A = { type: "a"; value: string };
type B = { type: "b"; value: number };
type Union = A | B;
function process(item: Union) {
// ❌ Destructuring loses discriminant information
const { type, value } = item;
// TypeScript now thinks 'value' is 'string & number' (never)
// ✅ Access properties directly
if (item.type === "a") {
console.log(item.value.toUpperCase()); // string
}
}Keep objects intact when working with discriminated unions and intersections.
When accessing properties dynamically, use generic constraints to avoid creating impossible intersections.
type Config = {
host: string;
port: number;
};
// ❌ Creates intersection: string & number
function getBadValue(key: keyof Config, config: Config) {
return config[key]; // Type is string & number (never)
}
// ✅ Use generics to preserve individual types
function getValue<K extends keyof Config>(key: K, config: Config): Config[K] {
return config[key]; // Type is Config[K]
}
const host = getValue("host", { host: "localhost", port: 3000 }); // string
const port = getValue("port", { host: "localhost", port: 3000 }); // numberGenerics allow TypeScript to track which specific key you're accessing, preserving the correct type.
If intersection types are creating impossible constraints, redesign your type structure.
// ❌ Conflicting property types
type Base = { config: { debug: boolean } };
type Extended = { config: { verbose: boolean } };
type Combined = Base & Extended; // config: { debug: boolean } & { verbose: boolean }
// ✅ Merge object types properly
type BetterBase = { config: { debug: boolean } };
type BetterExtended = { config: { debug: boolean; verbose: boolean } };
type BetterCombined = BetterExtended; // No intersection needed
// ✅ Or use nested intersections
type NestedCombined = { config: Base["config"] & Extended["config"] };
// Results in { config: { debug: boolean; verbose: boolean } }Ensure that when types intersect, their properties also intersect compatibly, or flatten the structure.
Intersection Type Mechanics: TypeScript computes intersections by taking the most specific type that satisfies all constraints. For object types, this means merging all properties. For primitive conflicts (like string & number), the result is never because no value can satisfy both.
Known Compiler Issues: Several TypeScript GitHub issues (#38113, #43366, #31694) document cases where intersection type assignability behaves unexpectedly, particularly with:
- Optional properties in object intersections
- Spread operators combined with intersections
- Generic rest parameters in intersection types
- Index signatures intersecting with explicit properties
Type Distributivity: Intersection types distribute over union types: (A | B) & C becomes (A & C) | (B & C). This can lead to unexpected never types if C conflicts with either A or B.
Workarounds for Edge Cases: When encountering compiler limitations with intersections:
- Use type assertions (as unknown as TargetType) as a last resort
- Split complex intersections into intermediate type aliases for better inference
- Consider using utility types like Pick, Omit, or Merge to construct types explicitly rather than relying on intersection inference
Performance Considerations: Deeply nested intersections can slow down type checking. Keep intersection depth shallow and use type aliases to simplify complex intersections for better IDE and compiler performance.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript