You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 03:40:21