我在Deno中遇到TypeScript泛型问题。
abstract class Packet {
public abstract read(): Uint8Array;
public abstract write(data: Uint8Array): void;
}
type PacketData = Packet | Uint8Array;
type HookCallbackResult<T extends PacketData> = T | null | undefined;
type HookCallback<T extends PacketData> = (data: T) => HookCallbackResult<T>;
interface HookCallbackInfo<T extends PacketData> {
packetType: typeof Packet | "any";
callback: HookCallback<T>;
}
let callbacks: HookCallbackInfo<PacketData>[] = [];
function hook<T extends PacketData>(packetType: typeof Packet | "any", callback: HookCallback<T>) {
callbacks.push({ packetType, callback });
// ^^^^^^^^
// error: TS2322 [ERROR]: Type 'HookCallback<T>' is not assignable to type 'HookCallback<PacketData>'.
// Types of parameters 'data' and 'data' are incompatible.
// Type 'PacketData' is not assignable to type 'T'.
// 'PacketData' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'PacketData'.
// Type 'Packet' is not assignable to type 'T'.
// 'Packet' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'PacketData'.
}
我的目的是强制将回调作为第二个参数传递给hook
函数,以返回与其参数OR null
OR undefined
相同类型的结果,并且该类型应是Uint8Array
或已经解析过Packet
(或其子类),仅此而已。 hook
函数应存储此挂钩回调以供进一步使用。 Deno的TypeScript编译器版本在向对象数组(使用接口HookCallbackInfo
声明)中添加回调时感到恐慌。
我想我在泛型的某个地方犯了一个错误,因为我无法正确理解泛型如何使用这些多个类型定义(如Type1 | Type2 | Type3
)在TypeScript中工作。您能否解释一下我到底做错了什么以及如何以正确的方式做我想做的事情?
答案 0 :(得分:0)
您的callbacks
数组是HookCallbackInfo<PacketData>
个值的数组,这意味着它们的callback
字段必须包含类型为(data: PacketData) => HookCallbackResult<PacketData>
的函数。在hook
函数中,您传入的是扩展了T
的未知类型PacketData
的回调,因此您要提供的回调是类型{{1}的函数}。
这就是问题所在:(data: T) => HookCallbackResult<T>
需要可以在 any PacketData值上调用的函数,而您正在尝试为其提供只能在< em>一些 PacketData值。类型系统会检测到并阻止您这样做。
要弄清为什么这很重要,请考虑如果类型系统未对此进行检查会导致什么问题:
callbacks