【问题标题】:Using JavaScript Class Mixins with TypeScript Declaration Files将 JavaScript 类 Mixins 与 TypeScript 声明文件一起使用
【发布时间】:2020-02-03 23:19:21
【问题描述】:

我需要帮助在声明文件中使用类混合。具体来说,当在 mixin 中定义方法时,typescript 不会在混合类主体中提取它:

就我而言,我正在应用两个 mixin。第一个 mixin - NotifyingElementMixin - 提供了一个名为 notify 的方法,正是这个方法无法应用于混合类主体

notifying-element-mixin.js

export const NotifyingElementMixin = superclass =>
  class NotifyingElement extends superclass {
    /**
     * Fires a `*-changed` event.
     *
     * @param  {string}     propName Name of the property.
     * @param  {any} value  property value
     * @protected
     */
    notify(propName, value) {
      this.dispatchEvent(
        new CustomEvent(`${propName}-changed`, {
          detail: { value },
        })
      );
    }
  };
};

notifying-element-mixin.d.ts

export declare class NotifyingElement {
  public notify(propName: string, value: any): void
}

export function NotifyingElementMixin<TBase extends typeof HTMLElement>
(superclass: TBase): TBase & NotifyingElement;

第二个mixin提供了其他属性和方法,但是为了这个问题,我已经简化了实现

apollo-query-mixin.js

export const ApolloQueryMixin = 
  superclass => class extends superclass {
    data = null;
    is = 'Query';
  };

apollo-query-mixin.d.ts

export declare class ApolloQuery<TCacheShape, TData, TVariables, TSubscriptionData = TData> {
  data: null
  is: string
}

type Constructor<T = HTMLElement> = new (...args: any[]) => T;
export function ApolloQueryMixin<TBase extends Constructor, TCacheShape, TData, TVariables>
(superclass: TBase): ApolloQuery<TCacheShape, TData, TVariables> & TBase;

最后,我想导出一个类,它同时应用 mixins 并提供它自己的方法。这就是我遇到麻烦的地方

apollo-query.js

class ApolloQuery extends NotifyingElementMixin(ApolloQueryMixin(HTMLElement)) {
  /**
   * Latest data.
   */
  get data() {
    return this.__data;
  }

  set data(value) {
    this.__data = value;
    this.notify('data', value);
  }
  // etc
}

apollo-query.d.ts

import { ApolloQueryMixin } from "./apollo-query-mixin";
import { NotifyingElementMixin } from "./notifying-element-mixin";

export declare class ApolloQuery<TBase, TCacheShape, TData, TVariables>
extends NotifyingElementMixin(ApolloQueryMixin(HTMLElement)) {}

当我编译它或使用我的 IDE 时,我收到错误:

error TS2339: Property 'notify' does not exist on type 'ApolloQuery'.

如何让 typescript 在混合类主体中获取我继承的方法?

【问题讨论】:

    标签: javascript typescript mixins .d.ts


    【解决方案1】:

    这是我使用的mixin模式,我认为关键是返回构造函数:

    import { LitElement, property } from "lit-element";
    
    type Constructor = new (...args: any[]) => LitElement;
    
    interface BeforeRenderMixin {
      beforeRenderComplete: Boolean;
    }
    
    type ReturnConstructor = new (...args: any[]) => LitElement & BeforeRenderMixin;
    
    export default function<B extends Constructor>(Base: B): B & ReturnConstructor {
      class Mixin extends Base implements BeforeRenderMixin {
        @property({ type: Boolean })
        public beforeRenderComplete: boolean = false;
    
        public connectedCallback() {
          super.connectedCallback();
          if (!this.beforeRenderComplete)
            this.beforeRender().then(() => (this.beforeRenderComplete = true));
        }
    
        public async beforeRender() {
          return;
        }
    
        public shouldUpdate(changedProperties: any) {
          return this.beforeRenderComplete && super.shouldUpdate(changedProperties);
        }
      }
    
      return Mixin;
    }
    

    生成:

    import { LitElement } from "lit-element";
    declare type Constructor = new (...args: any[]) => LitElement;
    interface BeforeRenderMixin {
        beforeRenderComplete: Boolean;
    }
    declare type ReturnConstructor = new (...args: any[]) => LitElement & BeforeRenderMixin;
    export default function <B extends Constructor>(Base: B): B & ReturnConstructor;
    export {};
    

    【讨论】:

    • 这非常适合使用类来获取 mixin 方法,但是在 mixin 类的主体中,我不会从超类中获取类型,即如果我将 this 传递给函数期待一个 HTMLElement,我得到 Argument of type 'this' is not assignable to parameter of type 'HTMLElement'. 我会为此打开另一个问题
    猜你喜欢
    • 2019-12-10
    • 2013-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多