-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathindex.d.ts
233 lines (220 loc) · 7.03 KB
/
index.d.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import { Concat, Cast, Unshift, Reverse, Head, Tail } from '..';
// A binary tree is either empty or it has a value and two children, both of which are
// binary trees themselves.
//
// For example, here is how a binary tree can be visualized:
//
// 1
// / \
// / \
// 2 \
// / \ 3
// 4 5 / \
// 9 \
// 8
// / \
// 6 7
//
// A type to represent an empty tree.
export interface Empty {
empty: true;
}
// A type to represent a tree with a value and two children.
export interface Branch<
// The value this tree holds.
A,
// The left child.
L extends Tree<any, any, any>,
// The right child.
R extends Tree<any, any, any>
> {
value: A;
left: L;
right: R;
}
// A tree can either be empty or it's composed of a value and two children.
export type Tree<
A,
L extends Tree<any, any, any>,
R extends Tree<any, any, any>
> = Empty | Branch<A, L, R>;
// A helper type to create leaf trees (Trees that have no children).
export type Leaf<A> = Branch<A, Empty, Empty>;
// An example tree. Here's how it's visualized:
//
// a
// / \
// b c
// / \
// d f
// / \
// g e
//
export type Tree1 = Branch<
// Value.
'a',
// Left child.
Branch<
// Value.
'b',
// Left child.
Leaf<'d'>,
Empty
>,
// Right child.
Branch<
// Value.
'c',
// Left child.
Empty,
// Right child.
Branch<
// Value.
'f',
// Left child.
Leaf<'g'>,
// Right child.
Leaf<'e'>
>
>
>;
// Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures.
// One starts at the root (selecting some arbitrary node as the root in the case of a graph) and
// explores as far as possible along each branch before backtracking./
//
// As an example, the following will return an array with all values of a tree:
//
type S1 = DepthFirst<Tree1>; // ["a", "b", "d", "c", "f", "g", "e"]
//
// https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search.
//
// This type uses recursive (and not officially supported) type alias, see more:
// https://github.com/microsoft/TypeScript/issues/26223#issuecomment-513187373.
export type DepthFirst<
// The input tree.
T extends Tree<any, any, any>
> = {
//
finish: [];
//
// Computation is split into multiple steps with `infer`, see more:
// https://github.com/pirix-gh/medium/blob/master/types-curry-ramda/src/index.ts#L17.
next: T extends Branch<infer V, infer L, infer R>
? DepthFirst<L> extends infer G // Assign result to `G`
? DepthFirst<R> extends infer H // Assign result to `H`
? Concat<Cast<G, Array<any>>, Cast<H, Array<any>>> extends infer J // Assign result to `J`
? Unshift<Cast<J, Array<any>>, V>
: never
: never
: never
: never;
}[T extends Empty ? 'finish' : 'next'];
// Breadth-first search (BFS) is an algorithm for traversing or searching tree or graph data
// structures. It starts at the tree root (or some arbitrary node of a graph, sometimes referred
// to as a 'search key') and explores the neighbor nodes first, before moving to the next level
// neighbors.
//
// As an example, the following will return an array with all values of a tree.
//
type S2 = BreadthFirst<Tree1>; // ["a", "b", "c", "d", "f", "g", "e"]
//
// https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/breadth-first-search.
//
// This type uses recursive (and not officially supported) type alias, see more:
// https://github.com/microsoft/TypeScript/issues/26223#issuecomment-513187373.
export type BreadthFirst<
// The input tree.
T extends Tree<any, any, any>
> =
//
T extends Empty ? [] : Breadth<[T]>;
//
type Breadth<
//
Q extends Array<Tree<any, any, any>>,
//
R extends Array<any> = []
> = {
//
finish: R;
//
// Computation is split into multiple steps with `infer`, see more:
// https://github.com/pirix-gh/medium/blob/master/types-curry-ramda/src/index.ts#L17.
next: ExtractNodes<Q> extends infer G // Assign result to `G`
? ExtractValues<Q> extends infer J // Assign result to `J`
? Concat<R, Cast<J, Array<any>>> extends infer H // Assign result to `H`
? Breadth<Cast<G, Array<any>>, Cast<H, Array<any>>>
: never
: never
: never;
}[Q extends [] ? 'finish' : 'next'];
// A helper function to map over an array and call `ExtractValue` for each of the trees
// in the array.
//
type S3 = ExtractValues<[Branch<1, Leaf<2>, Leaf<3>>]>; // [1]
//
type ExtractValues<
// The array of trees to iterate over.
T extends Array<Tree<any, any, any>>,
// An accumulator to collect the results.
R extends Array<any> = []
> = {
// If the array is empty, return the accumulator.
finish: Reverse<R>;
// Otherwise, call `ExtractValue` on the first element of the array, add its results
// to the accumulator and run again recursively on the rest of the array.
next: ExtractValues<Tail<T>, Unshift<R, ExtractValue<Head<T>>>>;
}[T extends [] ? 'finish' : 'next'];
// A helper function to map over an array and call `ExtractNode` for each of the trees
// in the array.
//
type S4 = ExtractNodes<[Branch<1, Leaf<2>, Leaf<3>>]>; // [Leaf<2>, Leaf<3>]
//
type ExtractNodes<
// The array of trees to iterate over.
T extends Array<Tree<any, any, any>>,
// An accumulator to collect the results.
R extends Array<any> = []
> = {
// If the array is empty, return the accumulator.
finish: R;
// Otherwise, call `ExtractNode` on the first element of the array, add its results
// to the accumulator and run again recursively on the rest of the array.
//
// Computation is split into multiple steps with `infer`, see more:
// https://github.com/pirix-gh/medium/blob/master/types-curry-ramda/src/index.ts#L17.
next: Concat<R, ExtractNode<Head<T>>> extends infer H // Assign result to `H`
? ExtractNodes<Tail<T>, Cast<H, Array<any>>>
: never;
}[T extends [] ? 'finish' : 'next'];
// Extracts the value out of a tree.
type ExtractValue<
// The tree to extract the value out of.
T extends Tree<any, any, any>
> =
// Use `infer` to pattern-match the value inside the tree. See more:
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#type-inference-in-conditional-types.
T extends Tree<infer V, any, any> ? V : never;
// Extracts the sub-trees out of a tree.
type ExtractNode<
// The tree to extract from.
T extends Tree<any, any, any>
> =
// Check if the tree is a leaf (a tree with no children). If that's the case, return
// an empty array (no results).
//
// Then, check if the tree only has its right child and return an array with that one
// child.
//
// Next, do the same for the left child.
//
// Finally, if the tree has both of its child (not empty), return an array with both.
T extends Leaf<any>
? []
: T extends Tree<any, Empty, infer R>
? [R]
: T extends Tree<any, infer L, Empty>
? [L]
: T extends Tree<any, infer L, infer R>
? [L, R]
: never;