繁体   English   中英

Typescript:我如何最明确地定义一个可以保存 function 名称或该函数返回类型的变量?

[英]Typescript: how do I most explicitly define a variable that can hold a function name or that function's return type?

我正在重构/重建现有的代码库,并遇到了这段代码的等价物:


class FeedbackBase {
    Variables = [{Value: 'doSomething'}];

    goToFeedback() {

        this.Variables?.forEach(variable => {
            if (variable.Value) {
                variable.Value = (this[variable.Value])();
            }
        });
    }

    doSomething(): string { return '123';}
}

基本思想是Variables[].Value可能包含在FeedbackBase上定义的 function 调用。 如果是,则运行 function,并将Variables[].Value替换为返回值。

this.Variables?.forEach之前,他们最初是在做this.Variables的深度复制,消除所有输入并基本上在“任何”object 上运行代码。当我们继续输入时,Typescript 抱怨this[variable.Value]

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'FeedbackBase'. No index signature with a parameter of type 'string' was found on type 'FeedbackBase'.

很公平:Typescript 只知道variable.Value的内容是一个string :它不知道它是否是FeedbackBase上的可调用 function。

我的潜在解决方案:

type BaseFunction = {
    doSomething(): string;
};

class FeedbackBase implements BaseFunction {
    Variables = [{Value: 'doSomething'}];

    goToFeedback() {
        this.Variables?.forEach(variable => {
            if (variable.Value) {
                variable.Value = this[variable.Value as keyof BaseFunction]();
            }
        })
    }

    doSomething(): string { return '123';}
}

基本上:

  1. BaseFunction中,显式定义所有可以在variable.Value中定义的函数
  2. FeedbackBase implements BaseFunction
  3. 调用 function as this[variable.Value as keyof BaseFunction]告诉 Typescript 这应该被视为 function 调用,而不是字符串。

这种方法的一个很好的特点是,当你说this[variable.Value as keyof BaseFunction]时,Typescript 会检查以确保this确实具有BaseFunction中定义的所有函数。 (例如,如果您将FeedbackBase.doSomething更改为FeedbackBase.doSomethings ,则会在this[variable.Value as keyof BaseFunction]处出现错误)。

我认为,在这种情况下,我不得不使用as ,因为variable.Value可能是keyof BaseFunction ,或者 function 调用返回的任何内容。 即使我对返回类型有更具体的了解,我也想不出一种方法来定义variable.Value在转换之前绝对是一个 function 调用,并且在转换之后绝对是一个返回类型,除了使用as之外。

有没有办法更明确?

我不知道这是否是最好的 TypeScript 因为它看起来有点复杂,但我认为你的解决方案在打字方面很好。 我会提防一件事。

我不认为forEach会做你想做的事。 如果Value不是 function,您将收到运行时错误,因为您实际上并未检查Value是否为 function。相反,您正在检查它是否存在。

this.Variables?.forEach((variable) => {
      if (
        variable.Value &&
        variable.Value in this &&
        typeof this[variable.Value as keyof BaseFunction] === "function"
      ) {
        variable.Value = this[variable.Value as keyof BaseFunction]()
      }
})

如果 TS 知道你想做什么,它不会允许你这样做,我认为抱怨是正确的。 这就是这个答案将试图证明的。

您不需要接口来连接类型。 您可以像这样静态地计算出FeedbackBase非空方法名称的名称:

type NonVoidMethodNames<Class> = keyof {
    [K in keyof Class
        as ((...args: any[]) => void) extends Class[K] ? never
        : Class[K] extends (...args: any[]) => unknown ? K
        : never
    ]: K
}

type DoSomething = NonVoidMethodNames<FeedbackBase> // "doSomething"

如果您将它分配给如下所示的Variables ,则在调用this[variable.Value]()时不需要您的as

Variables: { Value: NonVoidMethodNames<FeedbackBase> }[] = [{ Value: 'doSomething' }];

TS 会尝试用"doSomething"索引this ,意识到这是一个方法,没问题,并按预期将返回类型计算为string

但当然我们不能简单地这样做,因为现在我们将string分配给variable.Value我们定义为"doSomething"

操场

在 TS 中,您不能编写以下内容,这就是您所处的情况,只能在两者之间进行间接访问。

let foo: string = 'a';
foo = 1;

如果您想将Value扩大到MethodName | ReturnType ,您也会感到不便。 MethodName | ReturnType当返回类型是string时,就像这里的情况一样,因为string会吞下它的子类型。

即使忽略Variables何时填充的问题,用户也无法知道该字段包含什么值。 在我看来,这是一个交易破坏者。 我对 OO 不是很了解,但我会说这种设计有缺陷,无法输入。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM