question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if youā€™re still stuck at the end, weā€™re happy to hop on a call to see how we can help out.

[BUG] Type for CellHyperlinkValue is wrong, sometimes has nested CellRichTextValue

See original GitHub issue

šŸ› Bug Report

Lib version: 4.2.0

Steps To Reproduce

  • Parse a xlsx file with lots of colours and hyperlinks.

The expected behaviour:

Cells including an hyperlink should follow the CellHyperlinkValue interface:

export interface CellHyperlinkValue {
	text: string;
	hyperlink: string;
}

The current behaviour:

Not all cells will match the given interface. We get cells nesting CellRichTextValue objects inside a linked cell:

{
  "text": {
    "richText": [
      {
        "font": {
          "underline": true,
          "size": 12,
          "color": {
            "indexed": 17
          },
          "name": "Calibri"
        },
        "text": "someone@somewhere.test"
      }
    ]
  },
  "hyperlink": "mailto:someone@somewhere.test"
}

Possible solution:

It might be enough to change the value for text on the CellHyperlinkValue interface. But I am not familiar enough with the innerworkings of ExcelJS to say wether this is enough:

export interface CellHyperlinkValue {
	text: string | CellRichTextValue;
	hyperlink: string;
}

It might need an even wider type for text? Maybe straight up CellValue if anything can be nested?

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:1
  • Comments:10 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
Zegnatcommented, Feb 28, 2022

@skypesky:

Are there any test files and test code to reproduce this error?

I will try to create an XLSX file that I am able to share publicly that shows this problem. Probably later tonight (CET). I havenā€™t found a clearcut way of creating these types of cells myself, but I should be able to copy one from an existing workbook and anonymise it.

@Wissam-Yelhow:

Iā€™m having to use cell.text.richText[0].text to get my value, and TypeScript isnā€™t happy with it.

weā€™re currently using:

return (cellValue as Exceljs.CellRichTextValue).richText.map(richText => richText.text).join(' ');

Be careful with your code there unless you are certain of the origin of your workbook! The same Excel file can contain hyperlink cells with and without nested richtext. If you cast all cell values as you are doing there you may end up casting actual string values to CellRichTextValue which will also break.

I like to take the defensive approach. I created a type alias with a fixed text and then another where I switch the old hyperlink type for the new one. This way TypeScript can continue to help me in writing code and making sure I cover all bases:

import { CellHyperlinkValue, CellRichTextValue, CellValue } from "exceljs";
// Dynamically modify the CellHyperlinkValue type to allow CellRichTextValue on `text`.
type DefensiveCellHyperlinkValue = {
    [key in keyof CellHyperlinkValue]: key extends "text" ? CellRichTextValue | string : CellHyperlinkValue[key];
};
// Swap the CellHyperlinkValue out for DefensiveCellHyperlinkValue.
type DefensiveCellValue = Exclude<CellValue, CellHyperlinkValue> | DefensiveCellHyperlinkValue;
// Use a function to recast into our defensive type.
const makeDefensivelyTyped = (cellValue: CellValue): DefensiveCellValue => cellValue;

With these I can cast a cellā€™s value and work on them knowing the hyperlink values are complete:

const cellValue = makeDefensivelyTyped(workbook.getWorksheet(1).getCell(1,1).value);
if (typeof cellValue === "object" && "hyperlink" in cellValue) {
    const text = cellValue.text; // Type here is now string | CellRichTextValue
    if (typeof text === "string") {
        return text;
    } else {
        return text.richText.map(({ text }) => text).join("");
    }
} else {
    // If the cell is not a hyperlink ā€¦
}

Not only can I hover the variable in VSCode to check the type every step of the way, in the else block after the typeof type narrowing it will also help me write the code as if the typings were always correct:

Screenshot: showing code completion for richText property on text variable.

1reaction
ajuvonencommented, Feb 22, 2022

The issue may be related to users who are saving .xlsx files with Apple Numbers, but I havenā€™t been able to verify this.

Read more comments on GitHub >

github_iconTop Results From Across the Web

exceljs - bytemeta
[BUG] Issue with web Component Ā· [BUG] Type for CellHyperlinkValue is wrong, sometimes has nested CellRichTextValue.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found