I am trying to create a module to export a docx using the npm docx package. However each time I run it I get the following error (even though the import is there). I checked for circular imports as well but can't identify any:
TypeError: docx_1.HeadingLevel is undefined
My code is as follows:
import { HeadingLevel, Document, Packer, Paragraph, TextRun, ImageRun } from 'docx';
const downloadObjectAsDocx = (exportObj: any, exportName: string) => {
// Function to generate the document
console.log(exportObj);
// Create document
const doc = new Document({
sections: [
{
properties: {},
children: [
// Title
new Paragraph({
text: exportObj.applicationInfo ? exportObj.applicationInfo.name : '',
heading: HeadingLevel.TITLE,
}),
// Description Header
new Paragraph({
text: 'Description',
heading: HeadingLevel.HEADING_1,
}),
// Description Content
new Paragraph({
children: [
new TextRun({
text: exportObj?.applicationInfo?.description || '',
break: 1,
}),
],
}),
// Architecture Header
new Paragraph({
text: 'Architecture',
heading: HeadingLevel.HEADING_1,
}),
// Architecture Image
new Paragraph({
children: [
new ImageRun({
data: exportObj?.architecture?.image || '', // base64 string from JSON
transformation: {
width: 500,
height: 300,
},
}),
],
}),
// Assumptions Header
new Paragraph({
text: 'Assumptions',
heading: HeadingLevel.HEADING_1,
}),
// Dynamically added Assumptions
...(exportObj.assumptions || []).map((assumption: any) =>
new Paragraph({
text: assumption.content,
bullet: {
level: 0,
},
}),
),
],
},
],
});
// Use Packer to generate a blob and simulate a download
void Packer.toBlob(doc).then(blob => {
const url = URL.createObjectURL(blob);
var downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute('href', url);
downloadAnchorNode.setAttribute('download', exportName + '.docx');
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
});
};
export default downloadObjectAsDocx;
Stacktrace:
I ran into this with other packages, and I say it's a misuse of typescript enums by the package.
export const HeadingLevel = {
HEADING_1: "Heading1",
HEADING_2: "Heading2",
HEADING_3: "Heading3",
HEADING_4: "Heading4",
HEADING_5: "Heading5",
HEADING_6: "Heading6",
TITLE: "Title",
} as const;
By setting this as a const object ... as const
instead of a proper enum, the types are technically available for hinting but they aren't really. So it looks like you're doing it correctly but then you run into an error at runtime.
This should have been declared as a normal enum:
export enum HeadingLevel {
HEADING_1: "Heading1",
HEADING_2: "Heading2",
HEADING_3: "Heading3",
HEADING_4: "Heading4",
HEADING_5: "Heading5",
HEADING_6: "Heading6",
TITLE: "Title",
};
And all would be well. I have had little success trying to get some people to use TS enums as they were intended; it's a whole tabs vs spaces
type debate in the JS/TS realm.
Instead of using the enum, use the value directly.
For example, this:
new Paragraph({
text: exportObj.applicationInfo ? exportObj.applicationInfo.name : '',
heading: HeadingLevel.TITLE,
})
Would become this:
new Paragraph({
text: exportObj.applicationInfo ? exportObj.applicationInfo.name : '',
heading: 'Title',
})