如何提供基于具有never
类型的参数之一的函数重载?
type Message<T> = { id: string };
function publish<T>(message: Message<T>, payload: T) {
// ...
}
如果T
是never
,这意味着消息从来没有有效负载,因此我不希望函数期望使用data
参数。
我重载了函数,为never
大小写提供了备用签名,这使得payload
参数成为可选的。
function publish(message: Message<never>, payload?: never): void
function publish<T>(message: Message<T>, payload: T): void {
// ...
}
这在Message<never>
情况下是可行的,但它中断了所有其他调用:
let NeverMessage: Message<never> = { id: "never-message" };
let NumberMessage: Message<number> = { id: "number-message" };
publish(NeverMessage);
// All good!
publish(NumberMessage, 10);
// function publish(message: Message<never>, payload?: undefined): void
// Argument of type '10' is not assignable to parameter of type 'undefined'
如何在不使payload
在两个签名中都具有可选性的情况下重载定义?
发布于 2019-09-27 16:57:21
你并不是真的像你想的那样过载这个函数。重载函数具有一个有序的调用签名列表,该列表对函数的调用者可见,并且没有实现(它们以;
而不是{...}
结尾),以及一个对函数的实现可见的单个实现签名。表面上,您希望调用方而不仅仅是实现来查看publish<T>(message: Message<T>, payload: T): void
签名。如果是这样的话,您需要这样做:
// call signatures
function publish(message: Message<never>, payload?: never): void;
function publish<T>(message: Message<T>, payload: T): void;
// implementation signature
function publish<T>(message: Message<T>, payload: T): void {
// ...
}
如前所述,这应该能解决你的问题。
顺便提一句,请注意气馁应该有一个泛型类型,如
type Message<T> = { id: string };
其中类型参数未使用。类型记录的类型系统主要是构造性,而不是名词,这意味着如果两种类型具有相同的结构,那么它们就是相同的类型,即使您使用不同的名称来引用它们。在这种情况下,Message<never>
和Message<number>
都是{ id: string }
,因此它们是相同的类型。
编译器可能会将显式类型为Message<never>
的表达式与显式类型为Message<number>
的表达式进行不同的处理,并且您的重载将以您想要的方式处理。但是,这并不能保证总是有效的,而且当它不起作用时,奇怪的东西也会发生。
这里的传统观点是在类型结构中的某个位置使用类型参数。甚至像这样的事情
type Message<T> = { id: string; __messageType?: T };
有时,即使在运行时不需要任何__messagetype
属性,也足以让事情正常工作。
您可能还需要小心处理子类型和超类型,因为即使在上面的Message<T>
定义中,Message<never>
也是任何Message<T>
的子类型,这意味着您可以在没有错误的情况下调用publish(NeverMessage, "hello there");
。值NeverMessage
将被视为有效的Message<"hello there">
。为了防止出现这种情况,您需要创建Message<T>
T
,如果您已经通过如下函数属性启用了--strictFunctionTypes
,就可以完成这一任务:
type Message<T> = { id: string; __messageType?: (x: T) => T };
您还需要扩大实现签名:
function publish(message: Message<never>, payload?: never): void;
function publish<T>(message: Message<T>, payload: T): void;
function publish<T>(message: Message<T> | Message<never>, payload?: T): void {
// ...
}
这将导致
publish(NeverMessage); // okay
publish(NumberMessage, 10); // okay
publish(NeverMessage, "hello there"); // error!
..。呃,但是我离题了,因为你不是在问这个。
您的主要问题的答案是记住添加一个单独的实现签名。
好吧,希望这能帮上忙,祝你好运!
https://stackoverflow.com/questions/58141316
复制相似问题