Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to solve TS7053 issue in replace method?

I have a problem. I’m trying to get data to be encoded and further used when downloading. All functionality works correctly and gives what I expect. But I get a typescript error when declaring the format constant in the place where the return occurs ( under context )

Error :
TS7053: Element implicitly has an ‘any’ type because expression of type ‘any’ can’t be used to index type ‘{ worksheet: string; table:string; }’.

Below is the code. Table is an element from the dom tree that I find by id

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  const template =
    '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-mic' +
    'rosoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta cha' +
    'rset="UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:Exce' +
    "lWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/>" +
    "</x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></" +
    "xml><![endif]--></head><body>{table}</body></html>";

  const context = {
    worksheet: "tablexls",
    table,
  };

const format = template.replace(/{(\w+)}/g, (m, p) => context[p]);

>Solution :

The issue is that TypeScript doesn’t know that p is a valid key for context. Maybe you don’t know that either, because you can’t be sure that all of the placeholders in the string are in fact valid keys for context; it depends on where that string comes from.

If you want to assume that it is, the fully type-safe way to do that is to have a type assertion function along these lines:

function assertsIsKeyOf<ObjectType>(object: ObjectType, key: string): asserts key is keyof ObjectType & string {
    if (!(key in object)) {
        throw new Error(`Key ${JSON.stringify(key)} expected but not found in object.`);
    }
}

Then your replace call would be:

const format = template.replace(/{(\w+)}/g, (m, p: string) => {
    assertsIsKeyOf(context, p);
    return context[p];
});

But you might not want to make that assumption, in which case you might want a type predicate instead:

function isKeyOf<ObjectType>(object: ObjectType, key: string): key is keyof ObjectType & string {
    return key in object;
}

Then the call is:

const format = template.replace(/{(\w+)}/g, (m, p: string) => {
    if (!isKeyOf(context, p)) {
        // Do something to handle the fact th ekey isn't valid, like throwing an error,
        // or returning a static value
        throw new Error(`Template has invalid key ${JSON.stringify(p)}`);
    }
    return context[p];
});

Playground link for all the above

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading