混合

TypeScript (和 JavaScript) 类只能严格的单继承,因此你不能做:

  1. class User extends Tagged, Timestamped { // ERROR : 不能多重继承
  2. // ..
  3. }

从可重用组件构建类的另一种方式是通过基类来构建它们,这种方式称为混合。

这个主意是简单的,采用函数 B 接受一个类 A,并且返回一个带有新功能的类的方式来替代 A 类扩展 B 来获取 B 上的功能,前者中的 B 即是混合。

TIP

「混合」是一个函数:

  • 传入一个构造函数;
  • 创建一个带有新功能,并且扩展构造函数的新类;
  • 返回这个新类。

一个完整的例子:

  1. // 所有 mixins 都需要
  2. type Constructor<T = {}> = new (...args: any[]) => T;
  3. /////////////
  4. // mixins 例子
  5. ////////////
  6. // 添加属性的混合例子
  7. function TimesTamped<TBase extends Constructor>(Base: TBase) {
  8. return class extends Base {
  9. timestamp = Date.now();
  10. };
  11. }
  12. // 添加属性和方法的混合例子
  13. function Activatable<TBase extends Constructor>(Base: TBase) {
  14. return class extends Base {
  15. isActivated = false;
  16. activate() {
  17. this.isActivated = true;
  18. }
  19. deactivate() {
  20. this.isActivated = false;
  21. }
  22. };
  23. }
  24. ///////////
  25. // 组合类
  26. ///////////
  27. // 简答的类
  28. class User {
  29. name = '';
  30. }
  31. // 添加 TimesTamped 的 User
  32. const TimestampedUser = TimesTamped(User);
  33. // Tina TimesTamped 和 Activatable 的类
  34. const TimestampedActivatableUser = TimesTamped(Activatable(User));
  35. //////////
  36. // 使用组合类
  37. //////////
  38. const timestampedUserExample = new TimestampedUser();
  39. console.log(timestampedUserExample.timestamp);
  40. const timestampedActivatableUserExample = new TimestampedActivatableUser();
  41. console.log(timestampedActivatableUserExample.timestamp);
  42. console.log(timestampedActivatableUserExample.isActivated);

让我们分解这个例子。

创建一个构造函数

混合接受一个类,并且使用新功能扩展它。因此,我们需要定义构造函数的类型:

  1. type Constructor<T = {}> = new (...args: any[]) => T;

扩展一个类并且返回它

  1. // 添加属性的混合例子
  2. function TimesTamped<TBase extends Constructor>(Base: TBase) {
  3. return class extends Base {
  4. timestamp = Date.now();
  5. };
  6. }

原文: https://jkchao.github.io/typescript-book-chinese/typings/mixins.html