tannerntannern / ts-mixer

A small TypeScript library that provides tolerable Mixin functionality.
MIT License
379 stars 27 forks source link

Proper constructor type hinting possible? #67

Open TaylorBenner opened 8 months ago

TaylorBenner commented 8 months ago

Is it possible to get proper constructor type hinting from something like the following?


/**
 * A helper type that defines generic arguments to a constructor.
 */
export type GenericArgs<T> = Record<PropertyKey, any> & T;

/**
 * @class
 */
export class LoggerAware {
  /**
   * @property { Types.Logger } logger
   * @protected
   * @readonly
   */
  protected readonly logger: Types.Logger;

  /**
   * @param { Types.GenericArgs & { logger: Types.Logger }} args 
   * @public
   * @constructor
   */
  public constructor(args: Types.GenericArgs<{ logger: Types.Logger }>) {
    this.logger = args.logger;
  };
};

/**
 * @class
 */
export class EmitterAware<T extends Types.EventMap> {
  /**
   * @property { Types.TypedEventEmitter<T> } emitter
   * @protected
   * @readonly
   */
  protected readonly emitter: Types.TypedEventEmitter<T>;

  /**
   * @param { Types.GenericArgs & { emitter?: Types.TypedEventEmitter }} args 
   * @public
   * @constructor
   */
  public constructor(args: Types.GenericArgs<{ emitter?: Types.TypedEventEmitter<T>}>) {
    this.emitter = args.emitter || new EventEmitter() as Types.TypedEventEmitter<T>;
  };
};

/**
 * @class
 */
export class CacheAware {
  /**
   * @property { Types.CacheInterface } cache
   * @protected
   * @readonly
   */
  protected readonly cache: Types.CacheInterface;

  /**
   * @param { Types.GenericArgs & { cache?: Types.CacheInterface }} args 
   * @public
   * @constructor
   */
  public constructor(args: Types.GenericArgs<{ cache?: Types.CacheInterface}>) {
    this.cache = args.cache || new MemoryCache();
  };
};

/**
 *
 */
export class Service extends Mixin(LoggerAware, CacheAware, EmitterAware) {
};

// This is very close to working.  I get inconsistent type hinting results.  
// It seems to cycle between any of the three args.
const service = new Service({ cache: '', logger: '', emitter: '' });