Skip to content

Instantly share code, notes, and snippets.

@cefn
Created November 9, 2022 02:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cefn/73f26fb02034165edf584ddbedcc39a4 to your computer and use it in GitHub Desktop.
Save cefn/73f26fb02034165edf584ddbedcc39a4 to your computer and use it in GitHub Desktop.
Interactive Story sketch
type Passage = string;
async function tell(passage: Passage): Promise<void> {}
async function choose<Choice extends string>(
passage: Passage,
choices: Record<Choice, Passage>
): Promise<Choice> {
return Object.keys(choices)[0] as Choice;
}
type AsyncFn = (...args: any[]) => Promise<any>;
interface Call<Fn extends AsyncFn> {
kind: "call";
fn: Fn;
args: Parameters<Fn>;
}
function* call<Fn extends AsyncFn>(
fn: Fn,
args: Parameters<Fn>
): Generator<Call<Fn>, Awaited<ReturnType<Fn>>, Awaited<ReturnType<Fn>>> {
return yield {
kind: "call",
fn,
args,
};
}
type CallStack<Fn extends AsyncFn, Ret> = () => Generator<
Call<Fn>,
Ret,
Awaited<ReturnType<Fn>>
>;
type StoryFn = typeof tell | typeof choose;
let roomId: RoomId = "lobby";
const story: CallStack<StoryFn, void> = function* () {
for (;;) {
const room = ROOMS[roomId];
roomId = yield* room();
}
};
const ROOMIDS = ["lobby", "bar", "cloakroom"] as const;
type RoomId = typeof ROOMIDS[number];
type Room = CallStack<StoryFn, RoomId>;
const lobby: Room = function* () {
yield* call(tell, ["hello"]);
return "bar";
};
const bar: Room = function* () {
yield* call(tell, ["hello"]);
return "cloakroom";
};
const cloakroom: Room = function* () {
yield* call(tell, ["hello"]);
return "lobby";
};
const ROOMS: Record<RoomId, Room> = {
lobby,
bar,
cloakroom,
} as const;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment