使用可选参数的键进行索引

Indexing with keys of optional parameters

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;
}

访问选项[key]抛出如下错误

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'.

如果 IHtmlProperties 没有可选参数,我可以轻松编写 options[key as keyof IHtmlProperties]。

不过这里的IHtmlProperties有一些可选参数。知道如何解决这个问题吗?

更新修复 较早的问题是因为 replace 具有未定义的值。因此检查值有效性修复了错误

        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;

接受的答案帮助我弄明白了!谢谢!

请看回答,与使用Object.keys相关。 因此,您已经知道 Object.keys returns 字符串数组。这意味着 forEach(function(key) 中的 keyoptions 的类型无关。换句话说,您只能使用 websitefavIcon 作为 options 的索引,而 key 的类型要宽得多,它是 string.

类型string"website" | "favIcon"keyof IHtmlProperties)的超类型,因此不允许使用。想象一下,您可以使用任何字符串作为 key: options["any string"]。此表达式 returns undefined 因为 "any string" 不能用于索引 options 对象。

让我们定义我们的函数:

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 您可能已经注意到,key 具有正确的类型。由于 replace 的第二个参数的预期类型是 string 我们不允许传递 undefined.

常量 value 具有 string | undefined 类型,这就是为什么它不允许作为参数。我们需要确保它是一个 string,这就是我添加三元运算符的原因。


版本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;
}