feat(commands): type command payload dispatch

This commit is contained in:
syntaxbullet
2026-07-03 09:50:39 +02:00
parent af71a49b09
commit d77bdc22a9
5 changed files with 24 additions and 5 deletions

View File

@@ -7,7 +7,7 @@ import { viewportPanCommand } from "./viewport";
describe("command dispatcher", () => {
test("throws for unknown commands", () => {
const store = createAppStore(createInitialAppState("Test"), createCommandRegistry([]));
expect(() => store.dispatch("missing", undefined)).toThrow("Unknown command: missing");
expect(() => store.dispatch("missing" as never, undefined as never)).toThrow("Unknown command: missing");
});
test("dispatch applies command result to store", () => {

View File

@@ -1,8 +1,9 @@
import type { AppState } from "@editor/state";
import type { CommandContext } from "./command";
import type { CommandId, CommandPayloads } from "./payloads";
import type { CommandRegistry } from "./registry";
export type Dispatch = <TPayload>(commandId: string, payload: TPayload) => AppState;
export type Dispatch = <TCommandId extends CommandId>(commandId: TCommandId, payload: CommandPayloads[TCommandId]) => AppState;
export type CommandDispatcher = {
dispatch: Dispatch;

View File

@@ -1,5 +1,6 @@
export type { Command, CommandContext } from "./command";
export type { CommandDispatcher, Dispatch } from "./dispatcher";
export type { CommandId, CommandPayloads } from "./payloads";
export { createCommandDispatcher } from "./dispatcher";
export type { CommandRegistry } from "./registry";
export { createCommandRegistry } from "./registry";

16
commands/payloads.ts Normal file
View File

@@ -0,0 +1,16 @@
import type {
ViewportPanPayload,
ViewportSetSizePayload,
ViewportSetZoomPayload,
ViewportZoomAroundPointPayload,
} from "./viewport";
export type CommandPayloads = {
"viewport.pan": ViewportPanPayload;
"viewport.setZoom": ViewportSetZoomPayload;
"viewport.zoomAroundPoint": ViewportZoomAroundPointPayload;
"viewport.setSize": ViewportSetSizePayload;
"viewport.reset": void;
};
export type CommandId = keyof CommandPayloads;

View File

@@ -1,4 +1,5 @@
import type { Dispatch } from "@commands/dispatcher";
import type { CommandId, CommandPayloads } from "@commands/payloads";
export type Keybind = string;
@@ -13,9 +14,9 @@ export type KeybindEvent = {
export type GlobalKeybindConsumer = (event: KeybindEvent) => boolean;
export type CommandKeybind = {
commandId: string;
payload?: unknown;
export type CommandKeybind<TCommandId extends CommandId = CommandId> = {
commandId: TCommandId;
payload: CommandPayloads[TCommandId];
};
export type KeybindMap = ReadonlyMap<Keybind, CommandKeybind>;