我无法理解如何正确地将作为参数传递的函数键入到另一个函数,其中传递的函数可以具有2个不同的签名,一个带有参数,另一个不带参数。
我的案件简化了:
type ApiMethod<T, U> = {
(payload?: T): Promise<U>;
};
function callFactory<T, U>(apiMethod: ApiMethod<T, U>) {
return async (payload?: T): Promise<U> => {
if (payload) {
return await apiMethod(payload);
} else {
return await apiMethod();
}
};
}
const apiMethodExample1: (payload: string) => Promise<string> = (payload) => {
return Promise.resolve('some payload: ' + payload);
};
const apiMethodExample2: () => Promise<string> = () => {
return Promise.resolve('no payload');
};
const call1 = callFactory(apiMethodExample1); // here TS complains
const call2 = callFactory(apiMethodExample2);
const value1 = call1('examplePayload').then((value: string) => console.log(value));
const value2 = call2().then((value) => console.log(value));
here the code in the TS playground
我的问题是TS抱怨
const call1 = callFactory(apiMethodExample1);
Argument of type '(payload: string) => Promise<string>' is not assignable to parameter of type 'ApiMethod<string, string>'.
Types of parameters 'payload' and 'payload' are incompatible.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
我觉得我没有正确地重载 apiMethod 参数 但我所有其他尝试也都失败了
我已经看过以下答案:Typescript function overloads with generic optional parameters
但无法将其应用于我的案子
感谢您的帮助
答案 0 :(得分:3)
给出这种类型:
T
如果您给我一个type ApiMethod<T, U> = {
(payload: T): Promise<U>;
(payload?: T): Promise<U>;
};
类型的值f
,我应该可以呼叫ApiMethod<string, string>
,并且我应该 也可以呼叫{{ 1}}。重载的函数具有多个调用签名,并且需要每个调用签名。
如果我打电话给f("someString")
,而一切都爆炸了,那么您还没有给我有效的f()
。这就是编译器为f()
抱怨的地方。
让我稍微修改ApiMethod<string, string>
的实现:
apiMethodExample1
我在这里所做的只是大写apiMethodExample1
,它是一个const apiMethodExample1: (payload: string) => Promise<string> = (payload) => {
return Promise.resolve('some payload: ' + payload.toUpperCase());
};
,因此它应该有一个payload
方法。从类型系统的角度来看,这与您的string
版本没有什么不同,因为从函数外部看不到实现细节。
如果编译器没有对此抱怨:
toUpperCase()
然后因为apiMethodExample1
的类型被推断为
const call1 = callFactory(apiMethodExample1);
所以您可以这样做:
call1
在运行时会爆炸
// const call1: (payload?: string | undefined) => Promise<string>
问题在于call1().then(s => console.log(s));
只能安全地用作// TypeError: payload is undefined
,而不能用作apiMethodExample1
所需的全套呼叫签名。
请注意,(payload: string): Promise<string>
很好,因为单个签名ApiMethod<string, string>
可分配给两个呼叫签名。 apiMethodExample2
可分配给() => Promise<string>
可能令人惊讶,但这是因为您可以安全地将前者用作后者,因为前者将忽略传递给它的任何参数。有关更多信息,请参见名为Why are functions with fewer parameters assignable to functions that take more parameters?的TypeScript常见问题解答条目。
此外:请注意,如果您的代码不仅仅是简化的示例,我强烈建议删除第一个重载签名,因为任何满足第二个重载签名的函数也将满足第一个重载签名。因此,这个特定示例实际上与过载本身并没有关系。如果您只是写,就会得到相同的行为
() => Promise<string>
好的,希望能有所帮助;祝你好运!
您似乎想输入(payload: string) => Promise<string>
来接受两种类型,而不是根本就不在乎type ApiMethod<T, U> = {
(payload?: T): Promise<U>;
};
。如果是这样,我会这样写:
callFactory()
内部没有条件代码;它只是将参数传播到调用中。然后键入ApiMethod<T, U>
,以便它返回的函数采用与传入的function callFactory<T extends [] | [any], U>(apiMethod: (...payload: T) => Promise<U>) {
return async (...payload: T): Promise<U> => {
return await apiMethod(...payload);
};
}
相同的参数。尚不清楚为什么您甚至需要callFactory
,因为它所做的只是返回与参数相同类型的东西(apiMethod
和callFactory
基本上是同一件事),但这只是您的简化示例代码,我猜。
无论如何,此后的一切都会起作用:
callFactory(apiMethodExample1)
希望有帮助。再次祝你好运。
答案 1 :(得分:0)
在使用此模式之前,我已经向类中的方法添加了“重载”。
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
int t = 4;
int f = ++t;
if(t<3)
{
if (f < 3)
Console.WriteLine("No");
}
else if(t>3)
{
Console.WriteLine("Yes");
if(f>3)
{
Console.WriteLine("DOUBLE YES");
break;
}
}
Console.WriteLine(f);
Console.WriteLine(t);
}