![](/img/trans.png)
[英]How can I define a return type of void for a function in a Typescript interface?
[英]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';}
}
基本上:
BaseFunction
中,显式定义所有可以在variable.Value
中定义的函数FeedbackBase implements BaseFunction
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.