export type DelayHoverElementProps<TElement extends HTMLElement> = React.HTMLProps<TElement>
& {
hoverDelay: number,
onHoverChanged: (isHovering: boolean) => void
};
export function DelayHoverElementFactory<
K extends keyof HTMLElementTagNameMap,
E extends HTMLElementTagNameMap[K],
C extends React.ComponentClass<DelayHoverElementProps<E>>
>(tagName: K): C {
return class extends React.Component<
DelayHoverElementProps<E>,
{ isHovering: boolean }
>{
constructor() {
super();
this.state = { isHovering: true };
}
private _delayTimer: NodeJS.Timer;
private onMouseOver = (e: React.MouseEvent<E>) => {
const { hoverDelay, onHoverChanged } = this.props;
clearTimeout(this._delayTimer);
this.setState({ isHovering: true }, () => {
this._delayTimer = setTimeout(() => {
onHoverChanged(true);
}, hoverDelay);
});
};
private onMouseOut = (e: React.MouseEvent<E>) => {
const { hoverDelay, onHoverChanged } = this.props;
clearTimeout(this._delayTimer);
this.setState({ isHovering: false }, () => {
this._delayTimer = setTimeout(() => {
onHoverChanged(false);
}, hoverDelay);
});
};
render() {
const { hoverDelay, onHoverChanged, ...props } = this.props;
const tagProps: React.HTMLProps<E> = {
...props,
onMouseOver: this.onMouseOver,
onMouseOut: this.onMouseOut
};
return React.createElement(tagName, tagProps);
}
} as any; // <---
}
这个测试用法:(摩卡,柴,sinon,酶;测试将通过)
const props: DelayHoverElementProps<HTMLDivElement> = {
hoverDelay: 200,
onHoverChanged: index => { },
className: 'test',
children: 'content'
};
const spy = sinon.spy(props, 'onHoverChanged');
const expected =
<div className="test" onMouseOver={()=>{}} onMouseOut={()=>{}}>content</div>;
const Div = DelayHoverElementFactory('div');
const actual = shallow(<Div {...props as any} />) // <---
// equalJsx is custom asserting method, with will convert JSX to string and compare that ...
expect(actual).to.equalJsx(expected);
actual.find('div').simulate('mouseOver');
expect(spy).to.be.not.called;
await new Promise(resolve => setTimeout(resolve, props.hoverDelay))
expect(spy).to.be.calledOnce;
expect(spy).to.be.calledWith(true);
我删除了这些as any
然后我收到了这些错误:
// first
Type 'typeof (Anonymous class)' is not assignable to type 'C'.
// second
Type '{ defaultChecked?: boolean; defaultValue?: string | string[]; suppressContentEditableWarning?: bo...' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<DelayHoverElementProps<HTMLDivElement>, ...'.
Type '{ defaultChecked?: boolean; defaultValue?: string | string[]; suppressContentEditableWarning?: bo...' is not assignable to type 'IntrinsicClassAttributes<Component<DelayHoverElementProps<HTMLDivElement>, ComponentState>>'.
Types of property 'ref' are incompatible.
Type 'Ref<HTMLDivElement>' is not assignable to type 'Ref<Component<DelayHoverElementProps<HTMLDivElement>, ComponentState>>'.
Type '(instance: HTMLDivElement) => any' is not assignable to type 'Ref<Component<DelayHoverElementProps<HTMLDivElement>, ComponentState>>'.
Type '(instance: HTMLDivElement) => any' is not assignable to type '(instance: Component<DelayHoverElementProps<HTMLDivElement>, ComponentState>) => any'.
Types of parameters 'instance' and 'instance' are incompatible.
Type 'Component<DelayHoverElementProps<HTMLDivElement>, ComponentState>' is not assignable to type 'HTMLDivElement'.
Property 'align' is missing in type 'Component<DelayHoverElementProps<HTMLDivElement>, ComponentState>'.
所以我在这里张贴这个并希望,有些打字大师会知道如何解决它...(as any
正在运作,但我不喜欢它 - 感觉不对)
答案 0 :(得分:0)
经过一番摆弄后,我最终得到了这段代码:
import * as React from 'react';
export type DelayHoverElementProps<TElement extends HTMLElement> =
React.HTMLProps<TElement> & {
hoverDelay: number,
onHoverChanged: (isHovering: boolean) => void
};
export function DelayHoverElementFactory<
K extends keyof HTMLElementTagNameMap,
E extends HTMLElementTagNameMap[K]
>(tagName: K): React.StatelessComponent<DelayHoverElementProps<E>> {
return function (props: DelayHoverElementProps<E>) {
const { hoverDelay, onHoverChanged, ...rest } = props;
let _delayTimer: NodeJS.Timer;
const onMouseOver = (e: React.MouseEvent<E>) => {
clearTimeout(_delayTimer);
_delayTimer = setTimeout(() => {
onHoverChanged(true);
}, hoverDelay);
};
const onMouseOut = (e: React.MouseEvent<E>) => {
clearTimeout(_delayTimer);
_delayTimer = setTimeout(() => {
onHoverChanged(false);
}, hoverDelay);
};
const tagProps: React.HTMLProps<E> = { ...rest, onMouseOver, onMouseOut };
return React.createElement(tagName, tagProps);
};
}
不再依赖于施放到any