Avoonix
Avoonix

Reputation: 33

Return type in emitted .d.ts files is any instead of this

I have created mixins as described here. When I'm editing the source files, the types are correct. However, the emitted .d.ts files have any instead of (in this case) PreComp types:

export class LottieItem {
  ...
}
export function Layers<TBase extends Constructor<LottieItem>>(
  Base: TBase
) {
  return class Layers extends Base {
    layers: Layer[] = [];

    addLayerFront(layer: Layer) {
      this.layers.unshift(layer);
      return this;
    }
    ...
  };
}
export class PreComp extends Layers(LottieItem) {
  ...
  // if I were to use this.addLayerBack() in here, it would return PreComp
}

declaration file after running tsc:

declare const PreComp_base: {
    new (...args: any[]): {
        [x: string]: any;
        layers: import("./Layer").Layer[];
        addLayerFront(layer: import("./Layer").Layer): any; // return value should not be any, but PreComp
    };
} & typeof LottieItem;
export declare class PreComp extends PreComp_base {
    ...
}

I also tried to use the alternative mixin pattern at the bottom of the page, but that caused properties of mixins not being initialized and methods being overridden (and thus not being callable using super).

Upvotes: 3

Views: 352

Answers (1)

6infinity8
6infinity8

Reputation: 325

A solution would be to declare the type of the Layers constructor:

interface Layers { // <- new declaration
    layers: Layer[];
    addLayerFront(layer: Layer): this;
}

export function Layers<TBase extends Constructor<LottieItem>>(
    Base: TBase
): TBase & Constructor<Layers> { // <- explicit type
    return class Layers extends Base {
        layers: Layer[] = [];

        addLayerFront(layer: Layer) {
            this.layers.unshift(layer);
            return this;
        }
    };
}

The resulting declaration would be the following:

interface Layers {
    layers: Layer[];
    addLayerFront(layer: Layer): this;
}
declare const PreComp_base: typeof LottieItem & Constructor<Layers>;
export declare class PreComp extends PreComp_base {}

The type of addLayerFront is preserved because it is now declared as part of an interface.

This solution is not perfectly optimal because it forces you to write the signatures of your methods twice, but it is type safe (no casts needed) and solves the problem.

Upvotes: 2

Related Questions