The foreword 0.

In learning and working with TypeScript, a few questions have puzzled me:

  1. For example, union types and cross types behave differently on the underlying and object types:
  • For basic types, a union type is a union of types, and an crossover type is an intersection of types.
// Union type
type Union = string | number // Union = string | number
// Cross type
type Intersection = string & number // Intersection = never
Copy the code
  • For object types, a union type is an intersection of properties, and a crossover type is a union of properties.
interface A {
  x: number
  y: number
}
interface B {
  y: number
  z: number
}
// Union type
type Union = A | B
/* Union = { y: number } */

// Cross type
type Intersection = A & B
/* Intersection = { x: number y: number z: number } */
Copy the code
  1. Let’s say the conditional typeextendsWhat exactly does keyword mean — inheritable? Extensible? Or is it assignable?
Extends => Extends => Extends?
type T1 = string extends string | number ? true : false // T1 = true

Extends => Extends?
interface ObjectA {
  x: string
  y: string
}
interface ObjectB {
  x: string
}
type T2 = ObjectA extends ObjectB ? true : false // T2 = true
Copy the code

As confusing as these examples are, maybe we should think about TypeScript’s type system in a different way: try thinking about it in terms of set theory.

1. Types and collections

In JavaScript, a type is a collection of values that satisfy certain characteristics. Such as:

  • numberThe type is the set of all the numbers.
  • stringA type is a collection of all strings.
  • boleanType istruefalseThe collection.
  • undefinedType isundefinedThe collection.

To sum up, types correspond to sets in set theory, and values correspond to elements in set theory. In TypeScript, we can declare a type for a variable and assign a value to that type.

let str: string = 'xxx'
str = 'yyy'
let num: number = 123
num = 456
Copy the code

When it comes to the type of an object, that is, a Class, the concept of a collection can be very confusing. Let’s look at the following example:

interface A {
  x: number
}
interface B {
  x: number
  y: number
}
const b: B = {
  x: 1.y: 2,}const a: A = b // ok
Copy the code

In this example, object B has type {x: number, y: number}, but it can be assigned to a variable of type {x: number}. This seemingly unreasonable phenomenon can be explained from the point of view of set theory: We regard class A, i.e. {x: number}, as the set of all objects with attribute x: number, that is, as long as we have attribute X: Any object of number can be viewed as an element of set A (or an instance of class A). Then because b = {x:1, y:2} has the attribute x: number => object B is an instance of class A => so b can be assigned to A variable A of type A. With respect to objects, it must be clear that an object type (class) is a collection of objects, not a collection of properties. An object is an element (instance) of the class as long as it has all the attributes described by the class.

2. Cross types and union types

  • Intersection Types correspond to Intersection of set theory
  • Union Types correspond to The Union of set theory

(PS: From the perspective of the original English translation, I think it would be more appropriate to translate crossover types and union types into intersection types and union types.)

2.1 Simple operation of cross type and union type

About cross type & and joint type | operation, let’s look at a simple example:

type A = 1 | 2
type B = 2 | 3
// The intersection of A and B
type C = A & B // C = 2
// Combine A and B
type D = A | B // D = 1 | 2 | 3
// A number intersection
type E = A & number // E = A = 1 | 2
// A number union
type F = A | number // F = number
/ / never empty set
type G = number & string // G = never
/ / the complete unknown
type H = number | unknown // H = unknown
Copy the code
  • A – F accords with the operation law of intersection and union of set theory
  • G neverMeans the type that will not appear, which conforms to the calculation law of empty set, and can be understood as empty set.
  • H unkonwnIt is an unknown type, which conforms to the calculation law of the complete set and can be understood as the complete set.

The operation properties of intersection and union in set theory, crossover and union types also satisfy: For the intersection operator & :

  1. Uniqueness:A & AIs equivalent toA.
  2. Satisfies the commutative law:A & BIs equivalent toB & A .
  3. Satisfy associative law:(A & B) & CIs equivalent toA & (B & C).
  4. Parent type convergence: if and only ifBAOf the parent type,A & BIs equivalent toA.

For operator and set | :

  1. Uniqueness:A | AIs equivalent toA.
  2. Satisfies the commutative law:A | BIs equivalent toB | A.
  3. Satisfy associative law:(A | B) | CIs equivalent toA | (B | C).
  4. Subtype convergence: if and only ifBAOf subtypes,A | BIs equivalent toA.

2.2 Advanced operation of cross type and union type

The same rules of set theory apply to cross and union types of object types:

Cross type advanced operations

interface A {
  x: number
  y: number
}
interface B {
  y: number
  z: number
}
// Cross type
type Intersection = B & A

const obj1: Intersection = {
  x: 1.y: 2.z: 3,
}

obj1.x // ok
obj1.y // ok
obj1.z // ok
Copy the code
  • Cross typeIntersectionIs an objectABThe intersection of, isThe intersection of a collection of objects“Is represented by ownershipABAll properties of, areThe union of a set of properties.
  • On assignment: Only hasABAll properties of the object can be assigned toIntersection.
  • On access: Cross typeIntersectionYou can visitABAll of the properties.

Union type high-level operations

interface A {
  x: number
  y: number
}
interface B {
  y: number
  z: number
}
// Union type
type Union = B | A

const obj1: Union = {
  x: 1.y: 2.z: 3,}const obj2: Union = {
  x: 1.y: 2,}const obj3: Union = {
  y: 2.z: 3,
}

obj1.x // error
obj1.y // ok
obj1.z // error
Copy the code
  • The joint typeUnionIs an objectABOf, i.eA union of collections of objects.
  • On assignment: YesAorBorA & BCan be assigned toUnion.
  • On access: Join types for type safetyUnionCan only accessABThere are properties.

3 Extends keyword

According to set theory, A extends B means that A is A subset of B.

3.1 Extends is used as a generic constraint

  • Expressions:T extends U
  • Action: Generic constraints are used to restrict the type of a generic, i.eGeneric type TIt must beThe type of UIn order to pass compilation.
function needNumber<T extends number> (value: T) :number {
  return value + 1
}
// Satisfy a subset of type number
needNumber(1) //ok
// Is not a subset of the number type
needNumber('1') //error
Copy the code

The same is true for object types:

interface Point {
  x: number
  y: number
}
function Sum<T extends Point> (value: T) :number {
  return value.x + value.y
}
// Satisfy a subset of the Point type
Sum({ x: 1.y: 2 }) // ok
Sum({ x: 1.y: 2.z: 3 }) // ok
// Not a subset of the Point type
Sum({ x: 1 }) // error
Copy the code

3.2 Extends is used as a conditional generic

  • Expressions:T extends U ? X : Y
  • Effect: The conditional type is a ternary operation expression ifTU, the value of the expression isX, or forU.
type IsNumber<T> = T extends number ? true : false
type Result1 = IsNumber<1> // true
type Result2 = IsNumber<'1'> // false
Copy the code

The same is true for object types:

interface Point {
  x: number
  y: number
}
type IsPointSubset<T> = T extends Point ? true : false
type Result1 = IsPointSubset<{ x: number; y: number} >// true
type Result2 = IsPointSubset<{ x: number; z: number} >// false
Copy the code

4. References

  • TypeScript Chinese manual
  • The basics of Typescript typing (1) Cross typing and union typing – understood from a set theory perspective