除了几种基本类型,TS 还有一些高级类型,其中包括交叉类型和联合类型这两种。
交叉类型(intersection types)
交叉类型可以让我们把现有的类型组合在一起得到一个新的类型,从而同时拥有它们的全部属性,表示方法是:A & B  。
interface IPerson {
  name: string;
  age: number;
}
interface IStudent {
  grade: number;
}
const getBio = (user: IPerson & IStudent) => {
  return `His name is ${user.name}, I am ${user.age} years old and a student of Grade ${user.grade}.`
}
getBio({name: ‘Joi’, age: 12, grade: 6})
跟集合里的相交不一样,TS 的交叉类型并不是指每个类型的交集,&  的意思理解成 and ,A & B  表示同时包含 A 和 B  的结果,这里传进去的 user 必须同时拥有 name, age, grade 这三个属性,我们可以直接使用它而不需要判断是否存在该属性。
联合类型(union types)
联合类型应该是我们在  TypeScript  使用得最多的特性之一,它使用管道符 | 把多个类型连起来,表示它有可能是这些类型中的其中一个:
const greet = (name: string | null) => {
  if (!name) {
    return `Hello, guest.`
  } else {
    return `Hello, ${name}.`
  }
}
强调有可能是因为它跟集合中的并不同,|  应该理解成 or ,A | B 表示 A 或 B 的结果,它只可能是其中一个,这也就意味着它的类型是不确定的。
interface ICat {
  run(): void
  meow(): void
}
interface IDog {
  run(): void
  bark(): void
}
class Cat implements ICat {
    run() { };
    meow() { };
}
const getAnimal = (): ICat | IDog {
    return new Cat();
}
const animal = getAnimal();
animal.run(); // ok
animal.meow(); // error
这里 ICat 和 IDog 都拥有 run 方法,我们不确定返回的具体是什么类型,如果想要编译通过就需要使用类型断言:
// 类型断言
(animal as ICat).meow() // ok
// 判断是否存在该方法
if (‘meow’ in animal) {
  animal.meow()
} else {
  animal.bark();
}
看起来它们的叫法换过来更符合直觉一点,至于为什么叫这两个名字,官方 repo 有个专门讨论这个问题的 issue] ,根据维护者的说法,这应该是约定俗成的,并不是他们刻意起的,是符合类型理论和其它语言的习惯的。
基于联合类型的条件类型分发
条件类型指的是 T extends U ? X : Y  ,在执行这条语句的时候,如果 T 是一个联合类型 A | B | C ,事实上它做的是: (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y) ,会在每个可能的类型分支上分别进行判断,最后得到的也是一个联合类型。基于这个特性,就可以做一些方便的操作:
// 移除属性值
type Diff<T, U> = T extends U ? never : T
type T1 = Diff<‘a’ | ‘b’ | ‘c’, ‘b’ | ‘d'> // ‘a’ | ‘c’