小鱼的博客 小鱼的博客
首页
  • 《ES6 教程》笔记
  • 《JavaScript教程》笔记
  • 《vue》笔记
  • 《git》学习笔记
  • 《TypeScript》学习笔记
  • 《Java教程》笔记
更多
  • 网站
  • 资源
  • Vue资源
分类
标签
归档
关于
友情链接
GitHub (opens new window)

小鱼

前端界的大佬,后端界的小学生
首页
  • 《ES6 教程》笔记
  • 《JavaScript教程》笔记
  • 《vue》笔记
  • 《git》学习笔记
  • 《TypeScript》学习笔记
  • 《Java教程》笔记
更多
  • 网站
  • 资源
  • Vue资源
分类
标签
归档
关于
友情链接
GitHub (opens new window)
  • 简介

  • 基础

    • 数据类型
    • 类型断言
    • 类型推论
    • 联合类型
    • 类型别名
    • 交叉类型
    • 可辨识联合
    • 类型保护与区分类型
    • TypeScript 函数
    • TypeScript 接口
    • TypeScript 类
    • TypeScript泛型
  • 《TypeScript》学习笔记
  • 基础
小鱼
2021-08-25

交叉类型

交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。 例如, Person & Serializable & Loggable同时是 Person 和 Serializable 和 Loggable。 就是说这个类型的对象同时拥有了这三种类型的成员。

我们大多是在混入(mixins)或其它不适合典型面向对象模型的地方看到交叉类型的使用。 (在JavaScript里发生这种情况的场合很多!) 下面是如何创建混入的一个简单例子:

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

class Person {
    constructor(public name: string) { }
}
interface Loggable {
    log(): void;
}
class ConsoleLogger implements Loggable {
    log() {
        // ...
    }
}
var jim = extend(new Person("Jim"), new ConsoleLogger());
var n = jim.name;
jim.log();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

交叉类型把几个类型的成员合并,形成一个拥有这几个类型所有成员的新类型。从字面上理解,可能会误认为是把取出几个类型交叉的(即交集)成员。

交叉类型的使用场景:Mixins、不适合用类来定义。

我觉得,交叉类型和Mixins有一点区别:交叉类型只是一个类型声明,用于类型约束;Mixins会给类增加成员,new对象时,对象会包含增加的成员属性。 我们看一看示例:

改自官方示例,官方示例有2个小问题:会提示不存在属性“hasOwnProperty”;另外,es6下prototype是不可以枚举的,无法通过枚举合并类属性。

  interface IAnyObject {
    [prop: string]: any
  }

  function extend<First extends IAnyObject, Second extends IAnyObject>(first: First, second: Second): First & Second {
    const result: Partial<First & Second> = {};
    for (const prop in first) {
      if (first.hasOwnProperty(prop)) {
        (result as First)[prop] = first[prop];
      }
    }
    for (const prop in second) {
      if (second.hasOwnProperty(prop)) {
        (result as Second)[prop] = second[prop];
      }
    }
    return result as First & Second;
  }

  interface IPerson {
    name: string,
    age: number
  }

  interface IOrdered {
    serialNo: number,
    getSerialNo(): number
  }

  const personA: IPerson = {
    name: 'Jim',
    age: 20
  }

  const orderOne: IOrdered = {
    serialNo: 1,
    getSerialNo: function () { return this.serialNo }
  }

  const personAOrdered = extend<IPerson, IOrdered>(personA, orderOne);
  console.log(personAOrdered.getSerialNo());

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

其中First & Second就是交叉类型的写法。

通过扩展,可以合并两传入对象的成员属性,增强现有对象的能力。

提示

如何这篇文章看不到,请阅读这篇文章交叉类型 (opens new window)

在 GitHub 上编辑此页 ! (opens new window)
#TypeScript
上次更新: 2021/09/03, 09:17:45
类型别名
可辨识联合

← 类型别名 可辨识联合→

最近更新
01
TypeScript泛型
08-26
02
TypeScript 类
08-26
03
TypeScript 接口
08-26
更多文章>
Theme by Vdoing | Copyright © 2021-2022 xiaoyu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式