interface Node[] = []> { value: T neighbors: Nodes } type A = Node<1, [B, C]> // Node<1, [Node<2>, Node<3>]> type B = Node<2, [A, D]> // Node<2, [Node<1>, Node<3>]> type C = Node<3, [A, B]> // Node<3, [Node<1>, Node<2>]> type D = Node<4, [B, C]> // Node<4, [Node<2>, Node<3>]> type FilterOut = Arr extends [ infer Head, ...infer Tail ] ? Head extends Target ? FilterOut : [Head, ...FilterOut] : [] type BFS< Root extends Node, ToFind, Searched extends Node[] = [] > = Root extends (Searched['length'] extends 0 ? never : Searched[number]) ? FilterOut extends [ infer Current extends Node ] ? BFS : never : Root['value'] extends ToFind ? Root & { __order: Searched } : Root['neighbors'] extends [ infer Current extends Node, ...infer Rest extends Node[] ] ? Current['value'] extends ToFind ? Current : Rest extends [infer Next extends Node] ? BFS : never : never type Result = BFS // Node<4, [Node<2>, Node<3>]> function breadthFirstSearch( root: Node[]>, toFind: T, searched: Node[] = [] ): Node | null { if (searched.includes(root)) return null if (root.value === toFind) return root as Node for (const current of root.neighbors) { if (current.value === toFind) return current const a = breadthFirstSearch(current, toFind, [...searched, root]) } return null }