Intersection types are closely related to union types, but they are used very differently. An interaction type combines multiple types into one. This allows you to add together existing types to get a single type that has all the features you need.
Commutativity: A & B is equivalent to B & A (except for call and construct signatures as noted below).
Associativity: (A & B) & C is equivalent A & (B & C).
Supertype collapsing: A & B is equivalent to A if B is a supertype of A.
Assignment compatibility
A & B is assignable to X if A is assignable to X or B is assignable to X.
X is assignable to A & B if X is assignable to A and X is assignable to B.
Properties and Index Signatures
The type A & B has a property P if A has a property P or B has a property P. If A has a property P of type X and B has a property P of type Y, then A & B has a property P of type X & Y.
Index signatures are similarly intersected.
Call and Construct Signatures
If A has a signature F and B has a signature G, then A & B has signatures F and G in that order (the order of signatures matter for purposes of overload resolution). Except for the order of signatures, the types A & B and B & A are equivalent.
Precedence
Similarly to expression operators, the & type operator has higher precedence than the | type operator. Thus A & B | C & D is parsed as (A & B) | (C & D).
Primitive Types
It is possible to intersect primitive types (e.g. string & number), but it is not possible to actually create values of such types (other then undefined). Because such types can result from instantiation of generic types (which is performed lazily), it is not possible to consistently detect and error on the operations that create the types.
import React from 'react';
export interface CommonComponentProps {
className?: string;
style?: React.CSSProperties;
classes?: Record<string, string>;
}
export type MixCommonComponentProps<T = any> = (
& Omit<CommonComponentProps, keyof T>
& T
);
export type MCCP<T = any> = MixCommonComponentProps<T>;
export type OverrideCommonComponentProps<X, Y> = (
& MixCommonComponentProps<Omit<X, keyof Y> & Y>
);
export type OCCP<X, Y> = OverrideCommonComponentProps<X, Y>;
export type OverrideCommonInputComponentProps<X, Y, T = any> = OCCP<Y, (
& {
value?: string | number;
name?: string;
onChange?: React.ChangeEventHandler<X>;
disabled?: boolean;
}
& T
)>;
export type OCICP<X, Y, T = any> = OverrideCommonInputComponentProps<X, Y, T>;
The result of intersection types always remain the most strict declaration
type X = { name: string } & { name?: string };
// Type '{}' is not assignable to type 'C'.
// Property 'name' is missing in type '{}' but required in type '{ name: string; }'.
const x: X = {};
type Y = { readonly name: string; } & { name?: string }
const y: Y = { name: 'abc' }
// Cannot assign to 'name' because it is a read-only property.(2540)
y.name = 'ABC';