TypeScript:键入功能混合

TypeScript: typing functional mixins

我正在尝试用 TypeScript 编写 functional mixins。这是我拥有的:

const flying = (o: object) => {
  let isFlying = false;

  return Object.assign({}, o, {
    fly() {
      isFlying = true;
      return this;
    },
    isFlying: () => isFlying,
    land() {
      isFlying = false;
      return this;
    }
  });
};

const quacking = (quack: string) => (o: object) =>
  Object.assign({}, o, {
    quack: () => quack
  });

const createDuck = (quack: string) => flying(quacking(quack)({}));
const duck = createDuck('Quack!');
duck.isFlying(); // TypeScript approves! ✅
duck.quack(); // TypeScript says there is no `quack` method! 

我的问题是,TypeScript 不知道鸭子也会叫。我怎样才能帮助 TypeScript 理解之前的 mixin 添加了什么?

(我认为错误与 o: object 有关......它需要以某种方式推断参数的类型,但要确保它是一个对象,以便 Object.assign 有效。其他语法可以使用扩展运算符 { ...o, ...{ /* ... flying or quacking ... */ } }.)

使用 TypeScript generics 来捕获输入参数的类型,而不是使用 object.

通过使用普通 object,TypeScript 丢失了有关原始输入类型的信息,并且只知道您添加的方法。使用泛型将允许 TypeScript 继承原始类型并将其与您的扩充正确组合。

const flying = <T extends {}>(o: T) => {
  let isFlying = false;

  return Object.assign({}, o, {
    fly() {
      isFlying = true;
      return this;
    },
    isFlying: () => isFlying,
    land() {
      isFlying = false;
      return this;
    }
  });
};

const quacking = <T extends {}>(quack: string) => (o: T) =>
  Object.assign({}, o, {
    quack: () => quack
  });

const createDuck = (quack: string) => flying(quacking(quack)({}));
const duck = createDuck('Quack!');
duck.isFlying(); // TypeScript approves! ✅
duck.quack(); // TypeScript approves! ✅

Playground Link.