Pasoul / blog

🛠 学习笔记 & 源码分析 & 代码规范 & 数据结构与算法
16 stars 3 forks source link

typescript手册-高级类型-联合类型、交叉类型 #21

Open Pasoul opened 5 years ago

Pasoul commented 5 years ago

联合类型

联合类型表示一个值的类型可以是多个类型中的一种,多个类型之间用竖线(|)分开,比如number|string表示类型既可以是number也可以是string

简单的例子

// 声明一个变量,值类型可以是number类型和string类型
let age: number|string = '10';
age = 10;

但是如果我们给age赋值的类型是其他类型,编译将会报错:

let age: number|string = '10';
age = 10;
age = true;
// Type 'true' is not assignable to type 'string | number'

访问联合类型的属性和方法

我们声明了一个函数,参数类型是联合类型number|string,然后在函数体内部尝试访问参数的length属性,这时编译报错:

function getSometing(arg:number|string) {
  console.log(arg.length);
}
Property 'length' does not exist on type 'string | number'.
  Property 'length' does not exist on type 'number'

typescript无法确定参数arg到底是哪个类型,我们只能访问联合类型中所有类型公有的属性和方法,很明显number类型的参数,没有length属性

如果我们访问numberstring的公有属性,是没问题的:

function getSometing(arg:number|string) {
  console.log(arg.toString());
}

稍复杂的例子

我们分别声明两个接口:ChickenDuck,它们分别有自己的方法:鸡会飞和生蛋,鸭子会游泳和生蛋 然后定义了doSomething函数,参数是animal,它的类型要么是Chicken要么是Duck

interface Chicken {
  fly();
  layEggs();
}

interface Duck {
  swim();
  layEggs();
}

function doSomething(animal:Chicken|Duck) {
  animal.fly();
}

如果我们调用animalfly方法,编译将会报错,因为typescript不知道animal的类型到底是Chicken还是Duck,如果我们传入的是Duck,很明显Duck是不会飞的(接口没有定义fly

Property 'fly' does not exist on type 'Chicken | Duck'.
  Property 'fly' does not exist on type 'Duck'

但是如果我们调用animallayEggs方法,编译通过,因为不管animal的类型是Chicken还是Duck,它们都拥有生蛋(layEggs)的能力,你可以大胆的调用。

function doSomething(animal:Chicken|Duck) {
  animal.layEggs();
}

参考:

Pasoul commented 5 years ago

交叉类型

类比前文的联合类型,交叉类型的含义是必须都要满足多个类型。

复用前文的例子,我们分别声明两个接口:ChickenDuck,它们分别有自己的方法:鸡会飞和生蛋,鸭子会游泳和生蛋。

然后定义了doSomething函数,参数是animal,但此时它的类型是Chicken&Duck,意味着animal的类型既要满足Chicken(会飞、会生蛋),也要满足Duck(会游泳、会生蛋)

interface Chicken {
  fly();
  layEggs();
}

interface Duck {
  swim();
  layEggs();
}

function doSomething(animal:Chicken&Duck) {
  animal.fly();
}

// 海鸥会飞、会游泳、会生蛋
let seagull = {
  fly() {},
  swim() {},
  layEggs() {}
}
doSomething(seagull);

因为同时满足所有类型,和联合类型的限制不同,可以访问交叉类型中所有类型的属性和方法

如果传入的参数不满足交叉类型的形状要求,编译将会报错:

let seagull = {
  swim() {},
  layEggs() {}
}
doSomething(seagull);
Argument of type '{ swim(): void; layEggs(): void; }' is not assignable to parameter of type 'Chicken & Duck'.
  Type '{ swim(): void; layEggs(): void; }' is not assignable to type 'Chicken'.
    Property 'fly' is missing in type '{ swim(): void; layEggs(): void; }