使用字符串访问 TypeScript 可选对象属性

Accessing TypeScript Optional Object Properties With a String

我在现有的 JavaScript 代码库中工作。有一个 class 公开了实用程序的预定义功能(例如“复制”、“粘贴”)。 class可以用“扩展”函数实例化,允许用户注册其他实用函数以备后用。

此代码未键入,因此我正在尝试将类型添加到签名中。但是我在使用按名称获取实用程序函数 (get(name)) 的函数时遇到了很多麻烦。代码的最小化版本(我尝试添加类型)如下:

class Operation {
    private extensions: {[key: string]: () => void}
    constructor(extensions: {[key: string]: () => void}) {
        this.extensions = extensions;
    }
    get(name: string): () => void {
        if (this[name]) {
            return this[name].bind(this)
        }
        if (this.extensions[name]) {
            return this.extensions[name].bind(this)
        }
        // default to copy
        return this.copy.bind(this);
    }
    copy() {
        console.log('copied');
    }
    paste() {
        console.log('pasted');
    }
}
const operation = new Operation({'cut': () => { console.log('cut'); }});
operation.get('cut')();

由于 this[name] 而失败:“元素隐式具有 'any' 类型,因为类型 'Operation' 没有索引签名 ts(7053)”。

由于此函数旨在接受任意字符串(由于覆盖),我认为我无法避免将函数键入 get(name: string)。我无法从 TypeScript 文档中弄清楚如何使用 conditional types,例如get(name: string | keyof Operation),我不认为这是正确的解决方案。

鉴于 name 不能保证是 属性 的 属性,使用严格类型(重新)构造和键入 get(name) 函数的最佳方法是什么17=]?

检查(在 JavaScript 中,而不是 TypeScript)被访问的密钥是直接在 class 上您想要允许的密钥之一 - 例如 copypaste。然后,TS 会自动推断允许这样的访问。

get(name: string): () => void {
    if (name === 'copy' || name === 'paste') {
        return this[name].bind(this)
    }
    if (this.extensions[name]) {
        return this.extensions[name].bind(this)
    }
    // default to copy
    return this.copy.bind(this);
}