I am implementing the following class:
export class BbSVGElement extends HTMLElement implements HTMLCanvasElement { ... }
The problem is that I can't find the type of the <svg>
element in typescript: <span>
elements are HTMLSpanElement
, <canvas>
elements are HTMLCanvasElement
, etc.
I ask because to implement a simple task such as the height()
function, I need to get the bounding box of the element. According to this stack overflow answer, this is the right way to do it:
height(): number { return this.getBBox().height}
But since this
refers to an HTMLElement
, of course Property 'getBBox' does not exist on type 'BbSVGElement'.ts(2339)
So I tried with castings of all kinds; things like:
return (<SVGElement> this).getBBox().width
return (<SVGSVGElement> this).getBBox().width
of course I could do something like
return (<any> this).getBBox().width
or
return this.offsetWidth // <-- This property here comes from HTMLElement
But I'd rather not if possible.
So: What would be the right casting to do? Or would there be another option I missed?
What is the type of the
<svg>
element in TypeScript?
The interface type of <svg>
elements in an *.svg
document (i.e. the SVG DOM) is SVGElement
. The type of an <svg>
element within a HTML document (i.e. the HTML DOM) is actually a prototype-less object that implements both HTMLElement
and SVGElement
!
So in TypeScript, you can represent an <svg>
element in the DOM by using an intersection type (which represents a type that combines all members of two or more types, compared to a union type which represents a type that combines shared members of two or more types).
Like so:
type SvgInHtml = HTMLElement & SVGElement;
const svgElement: SvgInHtml = document.createElement('svg') as SvgInHtml;
const svgHeight = svgElement.getBBox().height; // Using `SVGElement.getBBox()`.
const htmlWidth = svgElement.offsetWidth; // Using `HTMLElement.offsetWidth`
I see you want to represent this using a derived class - but that is incorrect (as class inheritance only allows a single parent class), instead either use a non-encapsulated type SvgInHtml
reference, or encapsulate it in an object or new class (with no superclass):
type SvgInHtml = HTMLElement & SVGElement;
class MySvgWrapper {
constructor( private readonly svgElement: SvgInHtml ) {
}
get height(): number {
return this.svgElement.getBBox().height;
}
}
(This is my original answer I posted before I understood your problem correctly - I'm keeping it here and accessible because I feel it may still be useful for other people who find this question but have a different problem to yours):
The base SVG-DOM interface for all (most?) SVG elements is SVGElement
which is documented on MDN.
Assuming you're using TypeScript 3.x or later which has the SVG-DOM interfaces in lib.dom.d.ts
(see the content of my answer below the line) then you need to change your class
declaration to this:
export class MySVGElement extends SVGElement {
}
Since TypeScript 3.x, TypeScript's "standard library" of typings for the HTML DOM includes the SVG DOM interfaces in lib/lib.dom.d.ts
, so you shouldn't need to download, import, or add anything - just use SVGElement
(and its derived interfaces) directly.
If you open the current TypeScript lib.dom.d.ts
in GitHub you can search for "SVGElement"
(and any other SVG-DOM interface, like SVGGraphicsElement
) and see it's declared in there:
e.g.:
/** SVG elements whose primary purpose is to directly render graphics into a group. */
interface SVGGraphicsElement extends SVGElement, SVGTests {
readonly transform: SVGAnimatedTransformList;
getBBox(options?: SVGBoundingBoxOptions): DOMRect;
getCTM(): DOMMatrix | null;
getScreenCTM(): DOMMatrix | null;
addEventListener<K extends keyof SVGElementEventMap>(type: K, listener: (this: SVGGraphicsElement, ev: SVGElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof SVGElementEventMap>(type: K, listener: (this: SVGGraphicsElement, ev: SVGElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
If you get any errors relating to unknown/undefined types then please post that as a new StackOverflow question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With