Why generate TypeScript interfaces from an XML sample?
TypeScript code consumes more XML than it admits to — feeds
fetched in the browser, SVG and sitemap processing, config
dialects, exports from tools that predate JSON. The usual path
converts the XML to a JavaScript object and then works
untyped, one runtime surprise at a time. Generating the
interfaces from a real sample inverts that: every element and
attribute in the sample gets a property with an inferred type,
repeated elements become arrays, sometimes-absent elements
become optional properties — and the layout deliberately
matches this site's XML to JSON converter, attributes under
"@attributes" and text under "#text",
so the types describe the objects you will actually hold.
How to use this tool
- Paste the XML, upload an .xml file, or drop one on the panel. The document must be well-formed; malformed input is reported with a line and column, not converted.
- Optionally name the root interface; left blank, it takes the root element's name. Decide on type inference — on for samples you trust, off if values are identifiers that merely look numeric.
- Press Generate TypeScript interfaces. The root interface comes first.
- Read the notes. Sometimes-absent attributes, mixed content and always-empty elements are listed there — review them before you rely on the result.
- Copy or download, and pair the interfaces with the XML to JSON converter's output (or your own parser configured to the same layout) so the types and the data stay in step.
The mapping rules
Elements. A child element becomes a property;
one that repeats anywhere becomes an array; one that is absent
from some parents becomes an optional property.
Attributes collect under
"@attributes", each typed from its values, and
optional there when some occurrences lack it.
Text. A leaf element's text types the
property — integer and decimal text are both
number, true/false is boolean, and a
slot that shows several shapes becomes their union rather
than a guess. Text alongside child elements collects under
"#text". Shapes. Elements with
identical structure share one interface. Property names keep
the XML name verbatim, quoted when it is not a valid
identifier — nothing is renamed silently.
Worked example
Given this catalogue fragment (note the second book has no price):
<catalog count="2">
<book id="bk101">
<title>Go in Practice</title>
<price>39.95</price>
</book>
<book id="bk102">
<title>XML Field Guide</title>
</book>
</catalog> the converter emits:
export interface Catalog {
"@attributes": { count: number };
book: Book[];
}
export interface Book {
"@attributes": { id: string };
title: string;
price?: number;
} Every judgement in that output is the sample's own evidence: the array is the second book, the question mark is the missing price, the attribute types are the values themselves.