【问题标题】:how to narrow the type for SVG Element union如何缩小 SVG 元素联合的类型
【发布时间】:2019-10-12 03:31:34
【问题描述】:

我正在使用 react 设置对 svg 元素的引用,该元素可能是 <rect><polygon><ellipse>

我有这个声明:

const shapeRef = useRef<SVGPolygonElement | SVGEllipseElement | SVGRectElement>(null);

但是当我尝试在 &lt;ellipse&gt; 元素上设置它时:

<ellipse
  cx={width / 8}
  cy={-sideDimension(y) / 8}
  rx={width}
  ry={height}
  ref={shapeRef}
/>

我收到此错误:

类型 'RefObject' 不能分配给类型 'string | ((实例: SVGEllipseElement |空)=> 无效)|参考对象 | 空 |不明确的'。类型“RefObject”不可分配给类型 '参考对象'。 类型 'SVGPolygonElement | SVGEllipseElement | SVGRectElement' 不可分配给类型 'SVGEllipseElement'。 “SVGPolygonElement”类型缺少“SVGEllipseElement”类型的以下属性:cx、cy、rx、ryts(2322)

对此我的理解是,我需要以某种方式缩小类型以使其工作,否则使用此 ref 的每个对象都必须具有联合的所有属性。

【问题讨论】:

  • 你看到我的回答了吗?有帮助吗?如果您需要更多帮助,请告诉我
  • 如果我的回答没有帮助,请与我交流,以便我进行更改。宽限期在 10 小时后结束
  • @Thatkookooguy 你现在应该有赏金了,如果你没有得到它,请告诉我
  • 谢谢!明白了:-)

标签: reactjs typescript svg


【解决方案1】:

你是对的。 Typescript 会出现该错误,因为它不知道应该将 shapreRef 记为哪一种类型。

IMO 的最佳解决方案是使用Type GuardsType Guard 是检查变量是否属于特定类型的打字稿方式。对于联合类型,这让 typescript 可以理解某些东西是特定类型的。

例如,在您的情况下,可能是这样的:

interface IEllipse {
  attr1: string;
  attr2: string;
}

interface IRect {
  attr3: string;
  attr4: string;
}

type SvgShape = IEllipse | IRect | IPolygon;

function isEllipse(shape: SvgShape): shape is IEllipse {
    return (shape as IEllipse).attr1 !== undefined;
}

注意返回类型是shape is IEllipse。这意味着打字稿将在这里解释一个真实的返回值,好像shape 是一个IEllipse

然后,无论你想在哪里使用SvgShape,你都可以检查它是哪种类型的SvgShape,打字稿应该知道基于它的类型:

// ...
render() {
  const shape: SvgShape = this.getCurrentShape();

  if (isEllipse(shape)) {
    // typescript should KNOW that this is an ellipse inside this if
    // it will accept all of Ellipse's attribute and reject other attributes
    // that appear in other shapes

    return <ellipse .../>;
  } else if (isRect(shape)) {
    // typescript should interpet this shape as a Rect inside the `if`

    return <rect ... />;
  } else {
    // typescript will know only one subtype left (IPolygon)

    return <polygon points="..." />;
  }
}
// ...

为什么不只是一个 Intersection 类型?

嗯...交叉类型更适用于每种类型(矩形、多边形等)在新项目中具有完全相同的属性的情况。 例如:

type Inter = IRect & IPolygon & IEllipse;

表示Inter 类型是IRectIPolygonIEllipse。这意味着这种类型的对象将具有所有三种类型的所有成员。 因此,尝试访问实际上是IRect 的形状上的属性points(存在于IPolygon)将表现得好像该属性存在于那里(我们不想要)

您将主要看到用于混合的交集类型和其他不适合经典面向对象模型的概念。

如何与 useRef 一起使用?

type SvgShape = SVGPolygonElement | SVGEllipseElement | SVGRectElement;

const shapeRef = useRef<SvgShape>(null);

function isEllipseRef(shapeRef: MutableRefObject<SvgShape>): shapeRef is MutableRefObject<IEllipse> {
  const shape: SvgShape = shapeRef.current;
  return (shape as IEllipse).attr1 !== undefined;
}

【讨论】:

    猜你喜欢
    • 2022-10-02
    • 2021-02-26
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 2021-10-21
    相关资源
    最近更新 更多