【问题标题】:Typescript: call a method by this + its name打字稿:通过这个+它的名字调用一个方法
【发布时间】:2021-08-31 03:49:23
【问题描述】:

我正在将一个项目转换为 Typsescript。这是一段艰难的旅程,但我正在一步一步地到达那里。不过,有一件事一直让我难以捉摸。

我可以在 纯 Javascript 中做到这一点:

class Example {
  callThis(methodName) {
    if (typeof this[methodName] === "function"){
      this[methodName]();
    }
  }

  getSomeText() {
    return this.someText;
  }

  setSomeText(someText) {
    this.someText = someText;
  }

  myMethod() {
    console.log(this.getSomeText());
  }

  myOtherMethod() {
    //etc
  }

  //and more methods that can be called with callThis()
}

const aTest = new Example;
aTest.setSomeText("calling myMethod()");
aTest.callThis("myMethod");

这运行良好并输出“调用 myMethod()”。当我将其转换为 Typescript 时,callThis 方法出现错误。它告诉我:

元素隐含地具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型“示例”。 在“示例”类型上找不到具有“字符串”类型参数的索引签名。

我怎样才能让 TypeScript 接受这个设置?稍后我将添加新的可调用方法,不仅仅是这个,所以我希望尽可能灵活。我已经创造了一些新的类型,但我在这个阶段还是个婴儿,所以请耐心等待。

这背后的整个想法是,该类用于从 HTML <template> 节点创建对话框,callThis 函数用于在节点添加到 DOM 后向其添加事件侦听器。

【问题讨论】:

  • 您为什么要这样做?为什么不一开始就调用你想要的方法呢?
  • 这让我觉得是 X-Y 问题和/或架构问题。像这样完全任意的设置几乎必须any 所覆盖,这违背了目的。我的第一种方法是为 name => impl 结构中的函数提供上下文,允许简单地键入上下文和函数。
  • @RobertoZvjerković 你说得对,我一直是隧道视觉的受害者。我想让一个函数完成所有渲染,然后调用该函数,但这是不必要的并且会污染渲染位。谢谢!附言。 Noobish here:我应该删除这个问题吗?

标签: javascript typescript


【解决方案1】:

解决方案是重写调用此类的代码,从而避免动态调用方法。 在尝试了建议作为答案的代码后,我的收获是:不要尝试在 TypeScript 中动态调用方法,没有简单的方法。

【讨论】:

    【解决方案2】:

    为了将其转换为打字稿,您需要编写自定义类型保护:

    const withoutParams = (fn: (...args: any) => any): fn is () => void =>
        fn.length === 0
    
    const isFunction = (fn: any): fn is () => void =>
        typeof fn === 'function'
    
    class Example {
        someText?: string;
    
        callThis<T,>(this: T, methodName: keyof T) {
            const x = this[methodName]
            if (isFunction(x) && withoutParams(x)) {
                x();
            }
        }
    
        getSomeText() {
            return this.someText;
        }
    
        setSomeText(someText: string) {
            this.someText = someText;
        }
    
        myMethod() {
            console.log(this.getSomeText());
        }
    
        myOtherMethod() {
        }
    
    }
    
    const aTest = new Example;
    aTest.setSomeText("calling myMethod()");
    aTest.callThis("myMethod");
    

    如果你想调用this[methodName],首先你需要向TS保证它是一个函数。然后你需要向 TS 保证这个函数没有参数。

    另外,你需要告诉 TS 你可能有someText 属性

    Playground

    【讨论】:

    • 不会真正起作用。 x 函数将使用错误的 this 范围调用,它会抛出。
    • @RobertoZvjerković 是对的,这在您调用 getSomeText 时没有定义。
    • 你可以像我在callThis中那样推断this
    【解决方案3】:

    这样的东西对我有用。我不确定您将如何传递参数...

    export class Example {
      private my_text = '';
      callThis(member: keyof Example): void {
        this[member](member);
      }
      getSomeText(): void {
        this.my_text = 'getSomeText';
      }
    
      setSomeText(): void {
        this.my_text = 'setSomeText';
      }
    }
    

    然后在 index.ts 中

    import { Example } from './Example';
    
    const lo_example = new Example();
    lo_example.callThis('getSomeText');
    

    【讨论】:

    • 这会调用lo_example.getSomeText('getSomeText')...不确定这就是OP想要的。
    • 按照我的理解,他想动态调用方法。他明白了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-27
    • 2016-02-18
    • 2017-12-24
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    相关资源
    最近更新 更多