将 JavaScript Class Mixins 与 TypeScript 声明文件一起使用
Using JavaScript Class Mixins with TypeScript Declaration Files
我需要帮助在声明文件中使用 class mixins。具体来说,当在 mixin 中定义方法时,typescript 不会在混合 class 主体中拾取它:
在我的例子中,我应用了两个混入。第一个 mixin - NotifyingElementMixin
- 提供了一个名为 notify
的方法,而这个方法未能应用于混合 class body
通知元素-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 },
})
);
}
};
};
通知元素-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;
最后,我想导出一个 class,它应用了两种混入并提供了它自己的方法。这就是我 运行 遇到麻烦的地方
阿波罗-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
}
阿波罗-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'.
我如何欺骗打字稿以在混合 class 主体中获取我继承的方法?
这是我使用的混合模式,我认为关键是 return 构造函数:
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 {};
我需要帮助在声明文件中使用 class mixins。具体来说,当在 mixin 中定义方法时,typescript 不会在混合 class 主体中拾取它:
在我的例子中,我应用了两个混入。第一个 mixin - NotifyingElementMixin
- 提供了一个名为 notify
的方法,而这个方法未能应用于混合 class body
通知元素-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 },
})
);
}
};
};
通知元素-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;
最后,我想导出一个 class,它应用了两种混入并提供了它自己的方法。这就是我 运行 遇到麻烦的地方
阿波罗-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
}
阿波罗-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'.
我如何欺骗打字稿以在混合 class 主体中获取我继承的方法?
这是我使用的混合模式,我认为关键是 return 构造函数:
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 {};