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
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]);
CodePudding user response:
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