I'm encountering an issue with TypeScript generics in Deno.
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'.
}
I am aiming to enforce a callback passed as the 2nd argument to the hook
function to return a result of the same type as its argument, null
, or
undefined</code. This type should either be a <code>Uint8Array
or a parsed Packet
(or one of its subclasses) and nothing else. Additionally, the hook
function should store this callback for future use. However, Deno's version of the TypeScript compiler throws an error when trying to add a callback to an object array declared with interface HookCallbackInfo
.
It seems like I may have erred in my usage of generics, as I find it challenging to grasp how they interact in TypeScript with multiple type definitions (like Type1 | Type2 | Type3
). Could you kindly explain where I went wrong and guide me on how to achieve my desired functionality in the correct manner?