TypeScript中如何声明已有DOM属性以允许TS识别并使用?
解决TypeScript结合Stimulus开发拖拽功能的预编译错误
嘿,作为TypeScript新手碰到这些类型错误太正常了,我来帮你逐个拆解并解决这些问题:
错误1: TS2339 - Element类型不存在draggable、ondragstart属性
原因:Stimulus Controller里的this.element默认被推断为Element类型,但draggable、ondragstart这些是HTMLElement特有的属性,TypeScript会严格检查类型匹配。
解决方法:在控制器类里显式声明element的类型为HTMLElement,让TypeScript能识别这些属性:
export default class MovablePipController extends Controller { // 新增这行,指定element的类型 element!: HTMLElement; static targets = [ "pipComponent", "topLeft", "topRight", "bottomLeft", "bottomRight" ]; // ... 其他代码 }
错误2: TS2322 - 事件回调类型不匹配,void无法赋值给DragEvent回调类型
这个错误有两个触发点:
ondragstart的回调参数类型不匹配ondragover的赋值写法错误(直接执行了event.preventDefault(),而非传递函数)
解决方法:
- 把
onDragStart的参数类型从Event改为DragEvent,匹配ondragstart的回调要求 - 修正
ondragover的赋值,传递一个接收DragEvent的函数,而不是直接执行结果:
connect(): void { // ... 其他代码 this.element.ondragstart = this.onDragStart.bind(this); this.topLeftTarget.ondragenter = () => this.movePipTo("top-left"); // 修正这里:传递函数,而不是直接调用preventDefault this.topLeftTarget.ondragover = (event) => event.preventDefault(); this.topRightTarget.ondragover = (event) => event.preventDefault(); this.bottomLeftTarget.ondragover = (event) => event.preventDefault(); this.bottomRightTarget.ondragover = (event) => event.preventDefault(); // ... 其他代码 } // 修改参数类型为DragEvent onDragStart(event: DragEvent): void { // ... 其他代码 }
错误3: TS2339 - Event类型不存在dropEffect属性
原因:dropEffect是DragEvent的专属属性,之前把参数类型写成Event,TypeScript自然找不到这个属性。
解决方法:就是上面提到的,把onDragStart的参数类型改为DragEvent,就能正常访问dropEffect了:
onDragStart(event: DragEvent): void { event.dropEffect = "none"; }
完整修正后的代码
import { Controller } from "stimulus"; import { polyfill } from "mobile-drag-drop"; // optional import of scroll behaviour import { scrollBehaviourDragImageTranslateOverride } from "mobile-drag-drop/scroll-behaviour"; polyfill({ dragImageTranslateOverride: scrollBehaviourDragImageTranslateOverride, }); export default class MovablePipController extends Controller { // 显式指定element类型为HTMLElement element!: HTMLElement; static targets = [ "pipComponent", "topLeft", "topRight", "bottomLeft", "bottomRight" ]; private pipComponentTarget!: HTMLCanvasElement; private topLeftTarget!: HTMLElement; private topRightTarget!: HTMLElement; private bottomLeftTarget!: HTMLElement; private bottomRightTarget!: HTMLElement; connect(): void { this.element.classList.add("bottom-right"); this.element.draggable = true; this.element.ondragstart = this.onDragStart.bind(this); this.topLeftTarget.ondragenter = () => this.movePipTo("top-left"); // 修正ondragover的赋值方式,传递事件处理函数 this.topLeftTarget.ondragover = (event) => event.preventDefault(); this.topRightTarget.ondragover = (event) => event.preventDefault(); this.bottomLeftTarget.ondragover = (event) => event.preventDefault(); this.bottomRightTarget.ondragover = (event) => event.preventDefault(); this.pipComponentTarget.dataset.corner = "bottom-right"; } // 参数类型改为DragEvent onDragStart(event: DragEvent): void { event.dropEffect = "none"; } movePipTo(corner: string): void { this.pipComponentTarget.dataset.corner = corner; } }
这样修改后,再执行rake assets:precompile应该就能顺利通过TypeScript的类型检查了。
内容的提问来源于stack exchange,提问作者Jason FB
相关产品推荐
相关产品推荐

