如何缩小 SVG 元素联合的类型

2024-03-21

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

我有这样的声明:

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

但是当我尝试将其设置为<ellipse>像这样的元素:

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

我收到此错误:

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

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


你是对的。 Typescript 会给你这个错误,因为它不知道应该考虑哪一种类型shapreRef as.

IMO 的最佳解决方案是使用类型保护装置 https://www.typescriptlang.org/docs/handbook/advanced-types.html. A 类型保护是检查变量是否属于某种类型的打字稿方法。对于联合类型,这使打字稿能够理解某些东西属于特定类型。

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

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

为什么不只是一个交叉点类型?

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

type Inter = IRect & IPolygon & IEllipse;

意味着一个Inter类型是IRect and IPolygon and IEllipse。这意味着该类型的对象将具有所有三种类型的所有成员。 因此,尝试访问该属性points(存在于IPolygon)实际上是一个形状IRect,将表现得好像该属性存在于此(我们不希望如此)

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

如何与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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何缩小 SVG 元素联合的类型 的相关文章

随机推荐

  • 获取 Flask 中的当前用户 ID

    我对 Python 还很陌生 老实说 我对一般编程也很陌生 我目前正在制定一种待办事项列表 我需要它将待办事项放入适当的课程中 所有这些都与教育内容相关 所以 问题很简单 我将其作为 Flask 驱动的路线 app route add co
  • 方案单词列表 eq?

    我有一个问题 我需要查找列表是否等于第二个列表 例如 set eq 1 2 3 1 2 3 gt t set eq 1 2 3 2 3 4 gt f 这些例子在我的程序中是正确的 但这个例子不是 set eq quote quote one
  • 如何使用GridView从服务器获取JSON数据--Flutter

    我参考过食谱 https flutter dev docs cookbook networking fetch data https flutter dev docs cookbook networking fetch data 示例代码是
  • VueJS 自定义 Props 验证功能

    我是 VueJS 的新手 所以我一直在关注他们的官方指南 https v2 vuejs org v2 guide components html Prop Validation 我能够触发前 5 个属性验证器 但我似乎无法触发最后一个示例
  • 在 Firefox 中读取多行内容可编辑文本

    让我们读取一个 contenteditable 元素 span This is editable br Yes it is span 就在您在文本末尾手动添加两个空格之后 I get textContent gt This is edita
  • C++ 中的“new”运算符何时调用构造函数

    自从我开始学习 C 以来 我一直读到 new 运算符在返回指向分配内存的指针之前调用对象的构造函数 因此 出于好奇 我检查了 new 的源代码 并在以下位置找到了以下内容 GLIBCXX WEAK DEFINITION void opera
  • 使用一组字符而不是一个字符的序列对齐算法

    Summary 我从一些有关对齐算法的细节开始 最后我提出了我的问题 如果您了解对齐算法 请从头开始 考虑我们有两个字符串 例如 ACCGAATCGA ACCGGTATTAAC 有一些算法 例如 史密斯 沃特曼 https en wikip
  • R 绘图自定义数据格式变体

    我正在尝试访问customdata通过javascrit分配给每个数据点 例如为每个点分配一个超链接 然而 我注意到数据格式从一个图变为另一个图 这看起来很奇怪 这在本例中完美运行 基于this https stackoverflow co
  • WordPress:single.php 不显示 the_content()

    我正在创建一个自定义 WordPress 主题 但我似乎无法让 single php 模板正常工作 下面是我写的代码 标题出现了 但内容没有出现 有什么想法为什么不是吗 div div id post gt h2 a href title
  • 为什么要对 List< 进行泛型转换?将 Set..> 扩展为 List 在 Sun JDK 6 上成功,但在 Oracle JDK 7 上编译失败?

    下面的代码 class GenericCompilationFailureDemo List
  • 类型 IUserStore`1 没有可访问的构造函数

    我想使用 Unity 3 设置 MVC5 应用程序 我从标准模板创建了一个默认的 Web mvc5 应用程序 然后添加了 unity 当我访问 AccountController 中的注册操作时 出现以下异常 类型 IUserStore 1
  • 使用对象元素作为参数的 Firestore 查询

    我在项目中使用 Firestore 作为数据库 并且我有一个表 我需要在对象内执行查询 foo data bar data exObject dataToQuery value 这是一个结构示例 我想在对象内部进行查询 一个如下所示的查询
  • 具有定向光正交投影的 OpenGL 3+

    我目前遇到来自移动 类似太阳 光源的定向光阴影贴图的问题 当我最初实现时 光投影矩阵被计算为 3D 并且阴影贴图看起来很漂亮 然后我了解到 对于我想要做的事情 正交投影效果会更好 但我很难替换正确的投影矩阵 正如人们所期望的那样 每次滴答声
  • 包含 unistd.h 的 write() 包装例程会导致错误

    我正在编写一个包装例程write 要覆盖原始系统功能 并在其中我需要通过执行另一个程序execve 我为其添加了头文件unistd h 我收到错误conflicting types for write usr include unistd
  • 如何让Three.js全屏显示?

    我想用 Three js 制作游戏 但如何使其全屏显示 我看见本文 http learningthreejs com blog 2011 11 17 lets make a 3d game make it fullscreen 并且我在代码
  • Hibernate,更改标识符/主键

    当我尝试更改我的设置时 我收到以下异常 ID in an Entity identifier of an instance of com google search pagerank ItemEntity was altered from
  • 无法创建 Laravel 项目,因为缺少 mcrypt 扩展

    好吧 我看过很多关于这个问题的帖子 我花了一整天的时间来解决这个问题 但没有成功 我正在尝试创建一个 Laravel 项目 我使用的是 Mac Yosemite 运行 PHP 5 5 14 机器上还有旧版本的 PHP 当我尝试使用 lara
  • ionic 如何添加空白页面作为应用程序的主页?

    我想使用选项卡式菜单将新页面添加到默认离子应用程序中 并将此页面显示为应用程序的默认页面 我尝试这样做的方法如下 我在 app js 中添加了新状态 state home url home views home templateUrl te
  • 是否可以让Head JS的ready()函数等待两个脚本?

    我在网页上加载了三个脚本 我想在其中两个脚本完成加载后触发一个函数 head js webfont http ajax googleapis com ajax libs webfont 1 0 31 webfont js jquery ht
  • 如何缩小 SVG 元素联合的类型

    我正在使用 React 设置对 svg 元素的引用 该元素可能是