StyledContainer传x/y属性报错:No overload matches for this call
解决"No overload matches for this call"错误
在给StyledContainer传入x、y属性时触发该错误,核心原因是StyledContainer的类型定义与传入的属性不匹配:当前代码直接将组件的Props接口传给了styled.div.attrs,但这个接口包含大量和容器样式无关的属性(比如onDragStart、onDragEnd等),且TypeScript无法识别你传入的x、y属于容器的合法属性。
修复方案
方案1:为StyledContainer单独定义专属属性接口
只保留容器需要的字段,避免类型冗余:
import React from "react"; import styled, { css } from "styled-components"; // 组件原有Props不变 interface Props { onDragStart?: () => void; onDragEnd?: () => void; children: React.ReactNode; isDragging: boolean; x?: number; y?: number; onDrag?: (position: { translateX: number; translateY: number }) => void; } // 新增StyledContainer专属属性接口 interface StyledContainerProps { x?: number; y?: number; isDragging: boolean; onMouseDown: (e: React.MouseEvent) => void; children: React.ReactNode; } interface State { originalX: number; originalY: number; lastTranslateX: number; lastTranslateY: number; translateX: number; translateY: number; isDragging: boolean; } export default class EventRecap extends React.Component<Props, State> { state = { isDragging: false, originalX: 0, originalY: 0, translateX: 0, translateY: 0, lastTranslateX: 0, lastTranslateY: 0, }; componentWillUnmount() { window.removeEventListener("mousemove", this.handleMouseMove); window.removeEventListener("mouseup", this.handleMouseUp); } handleMouseDown = ({ clientX, clientY }: { clientX: number; clientY: number }) => { window.addEventListener("mousemove", this.handleMouseMove); window.addEventListener("mouseup", this.handleMouseUp); if (this.props.onDragStart) { this.props.onDragStart(); } this.setState({ originalX: clientX, originalY: clientY, isDragging: true, }); }; handleMouseMove = ({ clientX, clientY }: { clientX: number; clientY: number }) => { const { isDragging } = this.state; const { onDrag } = this.props; if (!isDragging) { return; } this.setState( (prevState) => ({ translateX: clientX - prevState.originalX + prevState.lastTranslateX, translateY: clientY - prevState.originalY + prevState.lastTranslateY, }), () => { if (onDrag) { onDrag({ translateX: this.state.translateX, translateY: this.state.translateY, }); } }, ); }; handleMouseUp = () => { window.removeEventListener("mousemove", this.handleMouseMove); window.removeEventListener("mouseup", this.handleMouseUp); this.setState( { originalX: 0, originalY: 0, lastTranslateX: this.state.translateX, lastTranslateY: this.state.translateY, isDragging: false, }, () => { if (this.props.onDragEnd) { this.props.onDragEnd(); } }, ); }; render() { const { children } = this.props; const { translateX, translateY, isDragging } = this.state; return ( <StyledContainer x={translateX} y={translateY} isDragging={isDragging} onMouseDown={this.handleMouseDown} > {children} </StyledContainer> ); } } const StyledContainer = styled.div.attrs<StyledContainerProps>((props) => ({ // 给x/y加默认值,避免undefined导致样式异常 style: { transform: `translate(${props.x ?? 0}px, ${props.y ?? 0}px)` }, }))` cursor: grab; ${({ isDragging }) => isDragging && css` opacity: 0.8; cursor: grabbing; `}; `;
方案2:从组件Props中提取需要的字段
利用TypeScript的Pick工具类型,复用已有Props的部分字段:
import React from "react"; import styled, { css } from "styled-components"; interface Props { onDragStart?: () => void; onDragEnd?: () => void; children: React.ReactNode; isDragging: boolean; x?: number; y?: number; onDrag?: (position: { translateX: number; translateY: number }) => void; } // 提取StyledContainer需要的属性 type StyledContainerProps = Pick<Props, 'x' | 'y' | 'isDragging'> & { onMouseDown: (e: React.MouseEvent) => void; children: React.ReactNode; }; interface State { originalX: number; originalY: number; lastTranslateX: number; lastTranslateY: number; translateX: number; translateY: number; isDragging: boolean; } export default class EventRecap extends React.Component<Props, State> { state = { isDragging: false, originalX: 0, originalY: 0, translateX: 0, translateY: 0, lastTranslateX: 0, lastTranslateY: 0, }; componentWillUnmount() { window.removeEventListener("mousemove", this.handleMouseMove); window.removeEventListener("mouseup", this.handleMouseUp); } handleMouseDown = ({ clientX, clientY }: { clientX: number; clientY: number }) => { window.addEventListener("mousemove", this.handleMouseMove); window.addEventListener("mouseup", this.handleMouseUp); if (this.props.onDragStart) { this.props.onDragStart(); } this.setState({ originalX: clientX, originalY: clientY, isDragging: true, }); }; handleMouseMove = ({ clientX, clientY }: { clientX: number; clientY: number }) => { const { isDragging } = this.state; const { onDrag } = this.props; if (!isDragging) { return; } this.setState( (prevState) => ({ translateX: clientX - prevState.originalX + prevState.lastTranslateX, translateY: clientY - prevState.originalY + prevState.lastTranslateY, }), () => { if (onDrag) { onDrag({ translateX: this.state.translateX, translateY: this.state.translateY, }); } }, ); }; handleMouseUp = () => { window.removeEventListener("mousemove", this.handleMouseMove); window.removeEventListener("mouseup", this.handleMouseUp); this.setState( { originalX: 0, originalY: 0, lastTranslateX: this.state.translateX, lastTranslateY: this.state.translateY, isDragging: false, }, () => { if (this.props.onDragEnd) { this.props.onDragEnd(); } }, ); }; render() { const { children } = this.props; const { translateX, translateY, isDragging } = this.state; return ( <StyledContainer x={translateX} y={translateY} isDragging={isDragging} onMouseDown={this.handleMouseDown} > {children} </StyledContainer> ); } } const StyledContainer = styled.div.attrs<StyledContainerProps>((props) => ({ style: { transform: `translate(${props.x ?? 0}px, ${props.y ?? 0}px)` }, }))` cursor: grab; ${({ isDragging }) => isDragging && css` opacity: 0.8; cursor: grabbing; `}; `;
额外优化
在translate样式中给x、y添加默认值0,避免当x/y为undefined时生成无效的CSS语句。
内容的提问来源于stack exchange,提问作者Toriqul Islam Leon
相关产品推荐
相关产品推荐

