Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An intersection type combines multiple types into a single type that enforces the constraints of all constituent types simultaneously. Denoted by the ampersand (&) operator, a value of an intersection type must satisfy all type signatures defined across the intersected types.
type TypeA = { a: number };
type TypeB = { b: string };
type TypeC = { c: boolean };

type IntersectedType = TypeA & TypeB & TypeC;

Object Type Merging

When intersecting object types, the resulting type contains the union of all property keys from the constituent types. TypeScript preserves the intersection structure lazily (e.g., representing it as Identifiable & Auditable in the compiler). For non-overlapping properties, the original optionality modifiers are strictly maintained; if a unique property is optional in its constituent type, it remains optional in the intersection.
type Identifiable = { id: string };
type Auditable = { createdAt?: Date; updatedAt?: Date };

type Entity = Identifiable & Auditable;
// Preserved as `Identifiable & Auditable`.
// Structurally equivalent to an object requiring 'id', with optional 'createdAt' and 'updatedAt'.

Overlapping Properties and Optionality

If constituent types share a property key, the type of that shared property in the resulting intersection becomes the intersection of the overlapping types. The compiler maintains this representation without eagerly flattening nested structures.
type Left = { shared: { a: number }; uniqueLeft: string };
type Right = { shared: { b: boolean }; uniqueRight: number };

type Combined = Left & Right;
// Combined['shared'] is evaluated as `{ a: number } & { b: boolean }`
When overlapping properties have differing optionality modifiers, the required modifier strictly overrides the optional modifier. If a property is optional in one constituent type but required in another, the property becomes strictly required in the resulting intersection type.
type OptionalProp = { a?: string; b: number };
type RequiredProp = { a: string; c: boolean };

type MergedProps = OptionalProp & RequiredProp;
// Structurally equivalent to { a: string; b: number; c: boolean }
// 'a' becomes strictly required.

Mutually Exclusive Types and never

Intersecting mutually exclusive types (such as disjoint primitives) yields the bottom type, never, because no runtime value can simultaneously satisfy both constraints.
type StringAndNumber = string & number; // Evaluates to 'never'
When intersecting object types with overlapping properties of mutually exclusive non-unit types (such as string and number), the specific property evaluates to never, but the object type itself remains intact.
type X = { status: string };
type Y = { status: number };

type Z = X & Y; 
// Z evaluates to { status: never }
However, since TypeScript 3.9, if the conflicting properties are discriminant properties—specifically unit types such as literal types, true/false, null, or undefined—the compiler eagerly reduces the entire intersection type to never.
type Success = { status: 'success'; data: string };
type Failure = { status: 'error'; code: number };

type Result = Success & Failure;
// Result evaluates directly to 'never' because 'success' and 'error' are disjoint unit types.

Function Intersections

Intersecting multiple function signatures creates an overloaded function type. A function assigned to this intersection must be callable with any of the intersected signatures, effectively combining the parameter lists as overloads.
type StringProcessor = (x: string) => void;
type NumberProcessor = (x: number) => void;

type Processor = StringProcessor & NumberProcessor;
// Evaluates to an overloaded function type:
// ((x: string) => void) & ((x: number) => void)

Interaction with Top and Bottom Types

Intersection types have specific behaviors when evaluated against TypeScript’s top types (any and unknown) and the bottom type (never):
  • any: Intersecting any type T with any yields any, with the strict exception of never. The intersection any & never evaluates to never because the bottom type represents an empty set and overrides any in intersections.
  • unknown: Intersecting any type T with unknown acts as an identity operation, yielding T. Because unknown is the universal supertype, it imposes no additional constraints on T.
type WithAny = string & any;         // Evaluates to 'any'
type AnyAndNever = any & never;      // Evaluates to 'never'
type WithUnknown = string & unknown; // Evaluates to 'string'

Distributivity over Unions

Intersection distributes over union types. When an intersection operation involves a union, the TypeScript compiler applies the intersection to each member of the union individually, simplifying never types out of the final result.
type UnionA = 'x' | 'y';
type UnionB = 'y' | 'z';

type Intersection = UnionA & UnionB;

// Step 1: Distribute
// ('x' & 'y') | ('x' & 'z') | ('y' & 'y') | ('y' & 'z')

// Step 2: Evaluate intersections
// never | never | 'y' | never

// Step 3: Simplify
// Intersection evaluates to 'y'
Master TypeScript with Deep Grasping Methodology!Learn More