如何缩小SVG元素联合的类型 [英] how to narrow the type for SVG Element union

查看:117
本文介绍了如何缩小SVG元素联合的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using react to set a reference to an svg element that might be a <rect>, <polygon> or <ellipse>.

我有这个声明:

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

但是当我尝试将其设置在这样的<ellipse>元素上时:

But when I try and set this on an <ellipse> element like this:

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

我收到此错误:

类型'RefObject'不能分配给类型'string | ((实例: SVGEllipseElement | null)=> void)| RefObject | 空|不明确的'.类型"RefObject"不可分配给该类型 'RefObject'. 输入'SVGPolygonElement | SVGEllipseElement | SVGRectElement'不可分配给'SVGEllipseElement'类型. 类型"SVGPolygonElement"缺少类型"SVGEllipseElement"的以下属性:cx,cy,rx,ryts(2322)

Type 'RefObject' is not assignable to type 'string | ((instance: SVGEllipseElement | null) => void) | RefObject | null | undefined'. Type 'RefObject' is not assignable to type 'RefObject'. Type 'SVGPolygonElement | SVGEllipseElement | SVGRectElement' is not assignable to type 'SVGEllipseElement'. Type 'SVGPolygonElement' is missing the following properties from type 'SVGEllipseElement': cx, cy, rx, ryts(2322)

据此我的理解是,我必须以某种方式缩小类型才能使其正常工作,否则使用此引用的每个对象都必须具有联合的所有属性.

My understanding from this is that I somehow need to narrow the type in order for this to work or else every object that uses this ref must have all properties of the union.

推荐答案

您是正确的. Typescript会给您带来该错误,因为它不知道应将shapreRef解释为哪种类型.

You are correct. Typescript gives you that error because it doesn't know which one of the types it should account the shapreRef as.

IMO的最佳解决方案是使用类型保护. 类型防护是检查变量是否属于某种类型的打字稿方法.对于联合类型,它使打字稿理解某些东西是特定类型的.

The best solution IMO is using a Type Guards. A Type Guard is the typescript way to check if a variable is of a certain type. For union types, that gives typescript the understanding that something is of a specific type.

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

For example, in your case, it can be something like this:

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 .

Notice that the return type is shape is IEllipse. This means that typescript will interpret a truthy return value here as if shape is an IEllipse.

然后,无论您想在何处使用SvgShape,都可以检查它是SvgShape的类型,而打字稿则应基于该类型知道该类型:

Then, wherever you want to use a SvgShape, you can check which type of SvgShape it is and typescript should know the type based on that:

// ...
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="..." />;
  }
}
// ...

为什么不只是路口类型?

好吧...对于每种类型(Rect,Polygon等)中的每种类型在新项目中具有完全相同的属性的情况,相交类型更多. 例如:

Why not just an Intersection type?

Well... Intersection types are more for cases where every one of the types (Rect, Polygon, etc) have the exact same attributes in the new item. For example:

type Inter = IRect & IPolygon & IEllipse;

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

Means that an Inter type is IRect and IPolygon and IEllipse. That means an object of this type will have all members of all three types. So, trying to access the attribute points (which exists on IPolygon) on a shape that is actually an IRect, will act as if that attribute exists there (which we don't want)

您通常会看到用于混合的交集类型以及其他经典面向对象模型不适合的概念.

You will mostly see intersection types used for mixins and other concepts that don’t fit in the classic object-oriented mold.

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;
}

这篇关于如何缩小SVG元素联合的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆