TypeScript abstract class mixin with no constructor arguments

30 views Asked by At

I would like to have something like Rust traits for my application. I found that I can implement something similar in TypeScript using abstract classes and the Mixin function from the ts-mixer package:

import { Mixin } from "ts-mixer";

type Scale<T> = { normalize(value: T): number };

abstract class Arraylike<T> {
  abstract array: T[];
  valueAt(index: number) {
    return this.array[index];
  }
}

abstract class Scaleable<T> {
  abstract scale: Scale<T>;
  abstract valueAt(index: number): T;
  scaledAt(index: number) {
    return this.scale.normalize(this.valueAt(index));
  }
}

class ScaleContinuous {
  constructor(private min: number, private max: number) {}
  normalize(value: number) {
    return (value - this.min) / (this.max - this.min);
  }
}

class Numeric extends Mixin(Arraylike<number>, Scaleable<number>) {
  // The compiler rightly complains if `array` or `scale`are missing or don't match the generic
  constructor(public array: number[], public scale: ScaleContinuous) {
    super();
  }
}

const foo = new Numeric([4, 8, 5, 10], new ScaleContinuous(2, 10));

console.log(foo.scaledAt(0)); // 0.25
console.log(foo.scaledAt(1)); // 0.75

This works fine, however, it seems that the ts-mixer package does a lot of heavy lifting, such that it works with regular classes with constructor arguments, decorators, etc... My use case is much narrower, i.e. I would like to only mix abstract classes that have no constructor arguments (i.e. all data has to be implemented on the concrete class).

Is there perhaps some simpler way to do this than ts-mixer? I've tried to write my own mixin functions using the official TypeScript pattern, however, functions cannot return abstract classes, i.e.:

// This works
function FooMixin(base: Constructor) {
  return class extends base {};
}
// This does not
function FooMixin(base: any) {
  return abstract class extends base {};
}
0

There are 0 answers