'Is there a difference between `Extract` and the intersection `&`?

Given the following code:

type abc = "a" | "b" | "c"
type af = "a" | "f"

type T0 = Extract<abc, af>;
//    type T0 = "a"
type T2 = abc & af
//    type T0 = "a"

TS Playground

Is there any difference between Extract and &?



Solution 1:[1]

The intersection operator & is used to extend types (make a more specific type that is a subtype of each of the operands).

In contrast, the documentation says this about the Extract<Type, Union> utility:

Constructs a type by extracting from Type all union members that are assignable to Union.

In the case of literals (for example, number and string literals), these are equivalent: unions of literal types with less membership are more specific than unions with greater membership, so it simply works like the center, overlapping area of a Venn diagram in both cases:

venn diagram A & B

type Num = 1 | 2 | 3;
type Bin = 0 | 1;

type IntersectionN = Num & Bin; // 1
type ExtractionN = Extract<Num, Bin>; // 1

When considering object types, the two work very differently. Consider this example:

type A = {
  b: boolean;
  s: string;
};

type B = {
  b: boolean;
  n: number;
};

type IntersectionC = A & B;

declare const ci: IntersectionC;
ci.b // boolean
ci.n // number
ci.s // string

type ExtractionC = Extract<A, B>;

declare const ce: ExtractionC;
ce // never

The intersection of the two types creates a new object with the members of each input object.

In contrast, extracting from union A the members which are assignable to B yields never because A is not assignable to B.

TS Playground

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1