type BaseNode = { type: string }; type NodeOf = X extends { type: T } ? X : never; type SpecialisedVisitors = { [K in T['type']]?: Visitor, U, T>; }; export type Visitor = (node: T, context: Context) => V | void; export type Visitors = T['type'] extends '_' ? never : SpecialisedVisitors & { _?: Visitor }; export interface Context { next: (state?: U) => T | void; path: T[]; state: U; stop: () => void; visit: (node: T, state?: U) => T; }