Typescript satisfies condition with Record and generics does not work

50 Views Asked by At

This question is related to my other one How to store "types" and instantiate them dynamically in typescript.

Now I'm trying to add generics and abstract base classes into the mix. VsCode complains about everything. And I've tried to tweak the satisfies condition, but nothing works.

Here's the smallest reproducible Typescript Playground code:

export enum CommandType {
    Click = 'Click',
    NewTab = 'NewTab',
}

export interface AutomationCommand {
    id: string;
    type: CommandType;
}

export interface TabAutomationCommand extends AutomationCommand {
    id: string;
    type: CommandType;
    tabId: number
}

export abstract class SelectorCommand implements TabAutomationCommand {
    id: string = '';

    constructor(public type: CommandType, public tabId: number, public selector: string) { }
}

export class ClickCommand extends SelectorCommand {
    constructor(tabId: number, selector: string) {
        super(CommandType.Click, tabId, selector);
    }
}

export class NewTabCommand implements AutomationCommand {
    type: CommandType = CommandType.NewTab;
    id: string = '';

    constructor(public url?: string) { }
}

export class AutomationResponse<TResponse> {
    constructor(public id: string, public data: TResponse) { }
}

export interface CommandHandler<TCommand extends AutomationCommand, TResponse> {
    handle(command: TCommand): Promise<AutomationResponse<TResponse>>;
}

export abstract class TabCommandHandler<TCommand extends TabAutomationCommand, TResponse> implements CommandHandler<TCommand, TResponse> {
    constructor() { }

    abstract handle(command: TCommand): Promise<AutomationResponse<TResponse>>;
}

export class ClickCommandHandler extends TabCommandHandler<ClickCommand, boolean> {

    async handle(command: ClickCommand): Promise<AutomationResponse<boolean>> {
       throw Error('not implemented');
    }
}

export class NewTabCommandHandler implements CommandHandler<NewTabCommand, number>{
    constructor() { }

    async handle(command: NewTabCommand): Promise<AutomationResponse<number>> {
       throw Error('not implemented');
    }
}

//BELOW DOES NOT WORK
const handlers = {
        [CommandType.Click]: ClickCommandHandler,
        [CommandType.NewTab]: NewTabCommandHandler,
    } satisfies Record<CommandType, (new <TCommad extends AutomationCommand, TResponse>() => CommandHandler<TCommad, TResponse>)>;

async function execute<TCommand extends AutomationCommand, TResponse>(command: TCommand): Promise<AutomationResponse<TResponse>> {

        const handlerType = handlers[command.type];
        if (!handlerType)
            throw Error(`No handler found for command type '${command.type}'`)

        const handler = new handlerType();
        return await handler.handle(command);
    }

Error:

Type of computed property's value is 'typeof ClickCommandHandler', which is not assignable to type 'new <TCommad extends AutomationCommand, TResponse>(pageAwaiter: Awaiter, tabs: Map<number, TabSession>) => CommandHandler<TCommad, TResponse>'.
  Types of construct signatures are incompatible.
    Type 'new (pageAwaiter: Awaiter, tabs: Map<number, TabSession>) => ClickCommandHandler' is not assignable to type 'new <TCommad extends AutomationCommand, TResponse>(pageAwaiter: Awaiter, tabs: Map<number, TabSession>) => CommandHandler<TCommad, TResponse>'.
      Construct signature return types 'ClickCommandHandler' and 'CommandHandler<TCommad, TResponse>' are incompatible.
        The types of 'handle' are incompatible between these types.
          Type '(command: ClickCommand) => Promise<AutomationResponse<boolean>>' is not assignable to type '(command: TCommad) => Promise<AutomationResponse<TResponse>>'.
            Types of parameters 'command' and 'command' are incompatible.
              Type 'TCommad' is not assignable to type 'ClickCommand'.
                Type 'AutomationCommand' is missing the following properties from type 'ClickCommand': tabId, selector

This should be simple, what am I missing?

0

There are 0 best solutions below