Flow: SVG elements mistyped as Element instead of HTMLElement

Created on 25 Nov 2019  路  4Comments  路  Source: facebook/flow

Flow version: trunk

Expected behavior

SVG elements are actually of type HTMLElement.

document.createElement('svg') instanceof HTMLElement &&
document.createElement('animate') instanceof HTMLElement &&
document.createElement('circle') instanceof HTMLElement &&
document.createElement('defs') instanceof HTMLElement &&
document.createElement('ellipse') instanceof HTMLElement &&
document.createElement('g') instanceof HTMLElement &&
document.createElement('image') instanceof HTMLElement &&
document.createElement('line') instanceof HTMLElement &&
document.createElement('linearGradient') instanceof HTMLElement &&
document.createElement('mask') instanceof HTMLElement &&
document.createElement('path') instanceof HTMLElement &&
document.createElement('pattern') instanceof HTMLElement &&
document.createElement('polygon') instanceof HTMLElement &&
document.createElement('polyline') instanceof HTMLElement &&
document.createElement('radialGradient') instanceof HTMLElement &&
document.createElement('rect') instanceof HTMLElement &&
document.createElement('stop') instanceof HTMLElement &&
document.createElement('symbol') instanceof HTMLElement &&
document.createElement('text') instanceof HTMLElement &&
document.createElement('tspan') instanceof HTMLElement &&
document.createElement('use') instanceof HTMLElement
> true

Actual behavior

Currently they are typed as Element which is too restrictive (eg. when trying to use React refs with SVG elements)

Has PR Library definitions bug

Most helpful comment

No, because an SVGElement extends Element. The SVG spec even defines the SVGElement interface by extending from Element:

[Exposed=Window]
interface SVGElement : Element {

  [SameObject] readonly attribute SVGAnimatedString className;

  readonly attribute SVGSVGElement? ownerSVGElement;
  readonly attribute SVGElement? viewportElement;
};

SVGElement includes GlobalEventHandlers;
SVGElement includes DocumentAndElementEventHandlers;
SVGElement includes SVGElementInstance;
SVGElement includes HTMLOrSVGElement;

The "correct" way to create SVG elements via the DOM interface is like so:

document.createElementNS("http://www.w3.org/2000/svg", "svg") instanceof HTMLElement
// false

document.createElementNS("http://www.w3.org/2000/svg", "svg") instanceof SVGElement
// true

The way to address your flow error right now would be to do:

const ref = React.useRef<Element | null>(null);
return <svg xmlns="http://www.w3.org/2000/svg" ref={ref} />;

When/if the aforementioned PR gets merged the solution would be to do:

const ref = React.useRef<SVGElement | null>(null);
return <svg xmlns="http://www.w3.org/2000/svg" ref={ref} />;

All 4 comments

SVG is distinctly not part of the HTML spec. It has its own spec. Here is the PR you should be looking at: https://github.com/facebook/flow/pull/4551

Interesting. Would #4551 address the fact that this is a Flow error right now?

const ref = React.useRef<HTMLElement | null>(null);
return <svg ref={ref} />;

No, because an SVGElement extends Element. The SVG spec even defines the SVGElement interface by extending from Element:

[Exposed=Window]
interface SVGElement : Element {

  [SameObject] readonly attribute SVGAnimatedString className;

  readonly attribute SVGSVGElement? ownerSVGElement;
  readonly attribute SVGElement? viewportElement;
};

SVGElement includes GlobalEventHandlers;
SVGElement includes DocumentAndElementEventHandlers;
SVGElement includes SVGElementInstance;
SVGElement includes HTMLOrSVGElement;

The "correct" way to create SVG elements via the DOM interface is like so:

document.createElementNS("http://www.w3.org/2000/svg", "svg") instanceof HTMLElement
// false

document.createElementNS("http://www.w3.org/2000/svg", "svg") instanceof SVGElement
// true

The way to address your flow error right now would be to do:

const ref = React.useRef<Element | null>(null);
return <svg xmlns="http://www.w3.org/2000/svg" ref={ref} />;

When/if the aforementioned PR gets merged the solution would be to do:

const ref = React.useRef<SVGElement | null>(null);
return <svg xmlns="http://www.w3.org/2000/svg" ref={ref} />;

When/if the aforementioned PR gets merged

Aug 6, 2017

馃槅 馃槩

Was this page helpful?
0 / 5 - 0 ratings