export interface IHtmlProperties {
website?: string
favIcon?: string;
}
function getHtml(htmlTemplate: string, properties: IHtmlProperties) {
const options : IHtmlProperties = {
website: properties.website,
favIcon: properties.favIcon
};
let html = htmlTemplate;
Object.keys(options).forEach(function(key) {
html = html.replace('{{' + key + '}}', options[key]);//<==== Error
});
return html;
}
Accessing options[key] throwing error as below
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IHtmlProperties'.
No index signature with a parameter of type 'string' was found on type 'IHtmlProperties'.
If IHtmlProperties doesn't have optional params, I can easily write options[key as keyof IHtmlProperties].
But here IHtmlProperties has some optional parameters. Any idea how to solve this?
Update with fix The earlier problem is because of replace having the value of undefined. So checking for value validity fixed the error
let html = htmlTemplate;
(Object.keys(options)).forEach(function(key) {
const value = options[key as keyof IHtmlProperties];
if(value) {
html = html.replace('{{' + key + '}}', value);
}
});
return html;
The accepted answer helped me in figuring it out! Thanks for that!
Please see this answer, it is related in terms of using Object.keys
.
So, you already know that Object.keys
returns array of strings. It means that key
in forEach(function(key)
is not related to type of options
. In other words, you can use only website
and favIcon
as an index for options
whereas type of key
is much wider, it is a string
.
Type string
is a super type of "website" | "favIcon"
(keyof IHtmlProperties
), hence it is not allowed to use. Imagine you can use any string as a key
: options["any string"]
. This expression returns undefined
because "any string"
can't be used to index options
object.
Let's define our function:
export interface IHtmlProperties {
website?: string
favIcon?: string;
}
function getHtml(htmlTemplate: string, properties: IHtmlProperties) {
const options: IHtmlProperties = {
website: properties.website,
favIcon: properties.favIcon
};
let html = htmlTemplate;
return (Object.keys(options) as Array<keyof IHtmlProperties>).reduce((acc, key) => {
const value = options[key];
return value ? acc.replace('{{' + key + '}}', value) : acc
}, html);
}
Playground
As you might have noticed, key
has a correct type. Since expected type of second argument of replace
is a string
we are not allowed to pass undefined
.
Constant value
has string | undefined
type, thats why it is not allowed as an argument. We need to make sure that it is a string
, this is why I have added ternary operator.
Version with forEach
:
export interface IHtmlProperties {
website?: string
favIcon?: string;
}
function getHtml(htmlTemplate: string, properties: IHtmlProperties) {
const options: IHtmlProperties = {
website: properties.website,
favIcon: properties.favIcon
};
let html = htmlTemplate;
(Object.keys(options) as Array<keyof IHtmlProperties>)
.forEach((key) => {
const value = options[key];
if (value) {
html.replace(`{{${key}}}`, value)
}
});
return html;
}