如何提供基于具有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
成为可选的情况下重载定义?
答案 0 :(得分:2)
您并不是真正按照自己的想法overloading来使用此功能。重载的函数具有呼叫签名的有序列表,该函数的调用者可以看到它们并且没有实现(它们以;
而不是{...}
结尾),并且单个实现签名,该签名对于该函数的实现是可见的。表面上,您希望调用者(而不只是实现者)看到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 {
// ...
}
那应该可以解决您所说的问题。
顺便说一句,请注意,discouraged具有类似的通用类型
type Message<T> = { id: string };
其中type参数未使用。 TypeScript的类型系统主要是structural而不是标称系统,这意味着如果两个类型具有相同的结构,那么即使您使用不同的名称来引用它们,它们也都是相同的类型。在这种情况下,Message<never>
和Message<number>
都是{ id: string }
,因此它们是同一类型。
编译器可能会将显式键入为Message<never>
的表达式与显式键入为Message<number>
的表达式不同,并且您的重载可能会按照您想要的方式运行。但是不能保证这将始终有效,weird stuff可能会在不起作用时发生。
这里的传统观点是在类型结构中的某处使用类型参数。甚至像
type Message<T> = { id: string; __messageType?: T };
即使在运行时不需要任何__messagetype
属性,有时足以使事情工作。
您可能还需要注意子类型和超类型,因为即使以上Message<T>
定义中,Message<never>
也是任何Message<T>
的子类型,这意味着您可以调用{{1 }},没有错误。值publish(NeverMessage, "hello there");
将被视为有效的NeverMessage
。为防止那,您需要制作Message<"hello there">
invariant in T
,如果您通过这样的函数属性启用了--strictFunctionTypes
,则可以完成此操作:< / p>
Message<T>
您还需要扩展实现签名:
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 {
// ...
}
...呃,但是我离题了,因为您没有问这个。 ?
主要问题的答案是记住要添加一个单独的实现签名。
好的,希望能有所帮助;祝你好运!