UNPKG

21.8 kBTypeScriptView Raw
1/**
2 * ```js
3 * import from from '@adamburgess/linq'
4 * const sequence = from(['an', 'iterable', 'here!']);
5 * // now use all the methods on sequence!
6 * ```
7 *
8 * See {@link AnySequence} for all the transformations you can do to a sequence.
9 * @module
10 */
11/** A sequence of values.
12 *
13 * To create me, use from:
14 * ```js
15 * const sequence = from(['an', 'iterable', 'here!']);
16 * // now use all the methods on sequence!
17 * ```
18*/
19export interface AnySequence<T> extends Iterable<T> {
20 /** Map each element to another
21 *
22 * ```js
23 * from([2, 1, 5]).map(x => x + 1)
24 * // => [3, 2, 6]
25 * ```
26 */
27 map<TResult>(f: (arg: T, index: number) => TResult): Sequence<TResult>;
28 /** Filters with a TS type assertion ('is'), narrowing to that type
29 *
30 * ```typescript
31 * function isNumber(x: number | string): x is number {
32 * return typeof x === 'number';
33 * }
34 * from(['string', 12, 'str']).where(isNumber)
35 * // => [12]
36 * // sequence is now Sequence<number>
37 * ```
38 */
39 where<TNarrowed extends T>(f: (arg: T | TNarrowed, index: number) => arg is TNarrowed): Sequence<TNarrowed>;
40 /** Filters with and narrows to a type
41 *
42 * ```typescript
43 * from(['string', 12, 'str']).where<number>(x => typeof x === 'number')
44 * // => [12]
45 * // sequence is now Sequence<number>
46 * ```
47 * note! must use generic type! otherwise this overload is not used, and the type is not narrowed.
48 */
49 where<TNarrowed extends T>(f: (arg: T | TNarrowed, index: number) => boolean): Sequence<TNarrowed>;
50 /** Filters with a predicate that must return a truthy value
51 *
52 * ```js
53 * from([5, 10, 20]).where(x => x >= 8)
54 * // => [10, 20]
55 * ```
56 */
57 where(f: (arg: T, index: number) => any): Sequence<T>;
58 /** Reverses the sequence.
59 *
60 * ```js
61 * from([2, 1, 5]).reverse()
62 * // => [5, 1, 2]
63 * ```
64 */
65 reverse(): Sequence<T>;
66 /** Project each element to get a key, and group all items by that key.
67 *
68 * ```js
69 * from([10, 15, 20]).groupBy(x => Math.trunc(x / 10))
70 * .map(g => ({ key: g.key, values: Array.from(g) }))
71 * // => [{ key: 1, values: [10, 15] },
72 * // { key: 2, values: [20] }]
73 * ```
74 */
75 groupBy<TKey>(keySelector: (arg: T) => TKey): ArraySequence<KeySequence<TKey, T>>;
76 /** Project each element to get a key, and group all items, each projected onto another type.
77 *
78 * ```js
79 * from([10, 15, 20]).groupBy(x => Math.trunc(x / 10), x => x.toString())
80 * .map(g => ({ key: g.key, values: Array.from(g) }))
81 * // => [{ key: 1, values: ['10', '15'] },
82 * // { key: 2, values: ['20'] }]
83 * ```
84 */
85 groupBy<TKey, TProject>(keySelector: (arg: T) => TKey, elementSelector: (arg: T) => TProject): ArraySequence<KeySequence<TKey, TProject>>;
86 /** Sort the array in ascending order of the selector
87 *
88 * ```js
89 * from([4, 1, 10]).orderBy(x => x)
90 * // => [1, 4, 10]
91 * ```
92 */
93 orderBy(keySelector: (arg: T) => string | number): OrderedSequence<T>;
94 /** Sort the array in ascending order of the selector, with a custom comparer
95 *
96 * ```js
97 * // Sort alphabetically, ignoring case.
98 * from(['A xylophone', 'a frog', 'a zoo']).orderBy(x => x, new Intl.Collator('en', { sensitivity: 'base' }).compare)
99 * // => ['a frog', 'A xylophone', 'a zoo']
100 * ```
101 */
102 orderBy<TKey>(keySelector: (arg: T) => TKey, comparer: ICompare<TKey>): OrderedSequence<T>;
103 /** Sort the array in descending order of the selector
104 *
105 * ```js
106 * from([4, 1, 10]).orderByDescending(x => x)
107 * // => [10, 4, 1]
108 * ```
109 */
110 orderByDescending(keySelector: (arg: T) => string | number): OrderedSequence<T>;
111 /** Sort the array in descending order of the selector, with a custom comparer
112 *
113 * ```js
114 * // Sort reverse alphabetically, ignoring case.
115 * from(['A xylophone', 'a frog', 'a zoo']).orderByDescending(x => x, new Intl.Collator('en', { sensitivity: 'base' }).compare)
116 * // => ['a zoo', 'A xylophone', 'a frog']
117 * ```
118 */
119 orderByDescending<TKey>(keySelector: (arg: T) => TKey, comparer: ICompare<TKey>): OrderedSequence<T>;
120 /** Take a maximum amount of elements
121 *
122 * ```js
123 * from([2, 1, 5]).take(2)
124 * // => [2, 1]
125 * ```
126 */
127 take(count: number): Sequence<T>;
128 /** Take elements while the predicate is true, then skips the rest
129 *
130 * ```js
131 * from([2, 3, 1, 5]).takeWhile(x => x >= 2)
132 * // => [2, 3]
133 * ```
134 */
135 takeWhile(predicate: (arg: T) => any): Sequence<T>;
136 /** Skip a number of elements before letting the rest through
137 *
138 * ```js
139 * from([2, 3, 1, 5]).skip(2)
140 * // => [1, 5]
141 * ```
142 */
143 skip(count: number): Sequence<T>;
144 /** Skip elements while the predicate is true, then take the rest
145 *
146 * ```js
147 * from([2, 3, 1, 5]).skipWhile(x => x >= 2)
148 * // => [1, 5]
149 * ```
150 */
151 skipWhile(predicate: (arg: T) => any): Sequence<T>;
152 /** Append another iterable to the end
153 *
154 * ```js
155 * from([1, 2]).append([3, 4])
156 * // => [1, 2, 3, 4]
157 * ```
158 */
159 append<TAppend>(iterable: Iterable<TAppend>): Sequence<T | TAppend>;
160 /** Prepend another iterable to the start
161 *
162 * ```js
163 * from([1, 2]).prepend([3, 4])
164 * // => [3, 4, 1, 2]
165 * ```
166 */
167 prepend<TPrepend>(iterable: Iterable<TPrepend>): Sequence<TPrepend | T>;
168 /** Get all distinct elements of the sequence using strict equality. First value wins.
169 *
170 * ```js
171 * from([1, 2, 2, 3]).distinct()
172 * // => [1, 2, 3]
173 * ```
174 */
175 distinct(): Sequence<T>;
176 /** Get all distinct elements of the sequence, mapping each element to a key that will be used for strict equality. First value wins.
177 *
178 * ```js
179 * from([10, 15, 20, 25, 30]).distinct(x => Math.trunc(x / 10))
180 * // => [10, 20, 30]
181 * ```
182 */
183 distinct(keySelector: (arg: T) => unknown): Sequence<T>;
184 /** Project each element to an iterable/array, then flatten the result
185 *
186 * ```js
187 * from(['1 2', '3 4']).flat(x => x.split(' '))
188 * // => ['1', '2', '3', '4']
189 * ```
190 */
191 flat<TProject>(projector: (input: T) => Iterable<TProject>): Sequence<TProject>;
192 /** Correlates the elements of two sequences based on matching keys. An inner join.
193 *
194 * ```js
195 * const appleTypes = [
196 * { name: 'green apple', id: 5 },
197 * { name: 'red apple', id: 2 },
198 * { name: 'yellow apple', id: 10 }
199 * ];
200 * const apples = [
201 * { name: 'golden delicious', type: 10 },
202 * { name: 'granny smith', type: 5 },
203 * { name: 'pink lady', type: 2 },
204 * { name: 'fuji', type: 2 },
205 * { name: 'unknown', type: 999 }
206 * ];
207 *
208 * from(apples).join(
209 * appleTypes,
210 * apple => apple.type,
211 * type => type.id,
212 * (apple, type) => `${apple.name}: ${type.name}`
213 * )
214 * // => [ 'golden delicious: yellow apple',
215 * // 'granny smith: green apple',
216 * // 'pink lady: red apple',
217 * // 'fuji: red apple' ]
218 * ```
219 */
220 join<TInner, TKey, TResult>(innerSequence: Iterable<TInner>, outerKeySelector: (arg: T) => TKey, innerKeySelector: (arg: TInner) => TKey, resultSelector: (outer: T, inner: TInner) => TResult): Sequence<TResult>;
221 /** Correlates the elements of two sequences based on matching keys, and groups everything in the other table.
222 *
223 * ```js
224 * const appleTypes = [
225 * { name: 'green apple', id: 5 },
226 * { name: 'red apple', id: 2 },
227 * { name: 'yellow apple', id: 10 }
228 * ];
229 * const apples = [
230 * { name: 'golden delicious', type: 10 },
231 * { name: 'granny smith', type: 5 },
232 * { name: 'pink lady', type: 2 },
233 * { name: 'fuji', type: 2 },
234 * { name: 'unknown', type: 999 }
235 * ];
236 *
237 * from(appleTypes).groupJoin(
238 * apples,
239 * type => type.id,
240 * apple => apple.type,
241 * (type, apples) => `${type.name}: ${apples.map(a => a.name).joinString(', ')}`
242 * );
243 * // => [ 'green apple: granny smith',
244 * // 'red apple: pink lady, fuji',
245 * // 'yellow apple: golden delicious' ]
246 * ```
247 */
248 groupJoin<TInner, TKey, TResult>(innerSequence: Iterable<TInner>, outerKeySelector: (arg: T) => TKey, innerKeySelector: (arg: TInner) => TKey, resultSelector: (outer: T, inner: Sequence<TInner>) => TResult): Sequence<TResult>;
249 /** Counts the number of elements in the sequence
250 *
251 * ```js
252 * from([2, 1, 5]).count()
253 * // => 3
254 * from([]).count()
255 * // => 0
256 * ```
257 */
258 count(): number;
259 /**
260 * Converts this sequence to an array.
261 * Note: If you are using this Sequence in a for..of loop, you do _not_ need this --
262 * you can use the sequence directly.
263 *
264 * ```js
265 * from([2, 1, 5]).toArray()
266 * // => [2, 1, 5]
267 * ```
268 */
269 toArray(): T[];
270 /** Converts this sequence to a Map. First key wins.
271 *
272 * ```js
273 * from([{ k: 'a', v: 123 }, { k: 'b', v: 456 }]).toMap(x => x.k, x => x.v)
274 * // => new Map([['a', 123], ['b', 456]])
275 * ```
276 */
277 toMap<TKey, TElement>(keySelector: (arg: T) => TKey, elementSelector: (arg: T) => TElement): Map<TKey, TElement>;
278 /** Converts this sequence into an object. First key wins.
279 *
280 * ```js
281 * from([{ k: 'a', v: 123 }, { k: 'b', v: 456 }]).toObject(x => x.k, x => x.v)
282 * // => { a: 123, b: 456 }
283 * ```
284 */
285 toObject<TKey extends PropertyKey, TElement>(keySelector: (arg: T) => TKey, elementSelector: (arg: T) => TElement): Record<TKey, TElement>;
286 /** Convert this sequence into a Set
287 *
288 * ```js
289 * from([2, 1, 1, 5]).toSet()
290 * // => new Set([2, 1, 5])
291 * ```
292 */
293 toSet(): Set<T>;
294 /** Map each element and convert the resulting sequence into a set
295 *
296 * ```js
297 * from([2, 1, 1, 5]).toSet(x => x + 1)
298 * // => new Set([3, 2, 6])
299 * ```
300 */
301 toSet<TProject>(projector: (arg: T) => TProject): Set<TProject>;
302 /** Get the first element in the sequence. Will throw if empty! Use firstOrDefault if no throw is wanted.
303 *
304 * ```js
305 * from([2, 1, 5]).first()
306 * // => 2
307 * from([]).first()
308 * // => throws
309 * ```
310 */
311 first(): T;
312 /** Get the first element in the sequence that matches a condition. Will throw if empty! Use firstOrDefault if no throw is wanted.
313 *
314 * ```js
315 * from([2, 1, 5]).first(x => x >= 4)
316 * // => 5
317 * from([2, 1, 5]).first(x => x < 0)
318 * // => throws
319 * ```
320 */
321 first(predicate: (arg: T) => any): T;
322 /** Get the first element in the sequence. If empty, returns undefined.
323 *
324 * ```js
325 * from([2, 1, 5]).firstOrDefault()
326 * // => 2
327 * from([]).firstOrDefault()
328 * // => undefined
329 * ```
330 */
331 firstOrDefault(): T | undefined;
332 /** Get the first element in the sequence that matches a condition. If empty or no matches, returns undefined.
333 *
334 * ```js
335 * from([2, 1, 5]).firstOrDefault(x => x >= 4)
336 * // => 5
337 * from([2, 1, 5]).firstOrDefault(x => x < 0)
338 * // => undefined
339 * ```
340 */
341 firstOrDefault(predicate: (arg: T) => any): T | undefined;
342 /** Get the _only_ element in the sequence. Will throw if empty or more than one element! Use singleOrDefault if no throw is wanted.
343 *
344 * ```js
345 * from([2]).single()
346 * // => 2
347 * from([2, 1, 5]).single()
348 * // => throws
349 * from([]).single()
350 * // => throws
351 * ```
352 */
353 single(): T;
354 /** Get the _only_ element in the sequence that matches a condition. Will throw if empty or more than one element! Use singleOrDefault if no throw is wanted.
355 *
356 * ```js
357 * from([2, 1, 5]).single(x => x >= 4)
358 * // => 5
359 * from([2, 1, 5]).single(x => x >= 1)
360 * // => throws
361 * ```
362 */
363 single(predicate: (arg: T) => any): T;
364 /** Get the _only_ element in the sequence. Returns undefined if empty or more than one element.
365 *
366 * ```js
367 * from([2]).singleOrDefault()
368 * // => 2
369 * from([2, 1, 5]).singleOrDefault()
370 * // => undefined
371 * ```
372 */
373 singleOrDefault(): T | undefined;
374 /** Get the _only_ element in the sequence that matches a condition. Returns undefined if empty or more than one element.
375 *
376 * ```js
377 * from([2, 1, 5]).singleOrDefault(x => x >= 4)
378 * // => 5
379 * from([2, 1, 5]).singleOrDefault(x => x >= 1)
380 * // => undefined
381 * ```
382 */
383 singleOrDefault(predicate: (arg: T) => any): T | undefined;
384 /** Get the last element in the sequence. Will throw if empty! Use lastOrDefault if no throw is wanted.
385 *
386 * ```js
387 * from([2, 1, 5]).last()
388 * // => 5
389 * from([]).last()
390 * // => throws
391 * ```
392 */
393 last(): T;
394 /** Get the last element in the sequence that matches a condition. Will throw if empty! Use lastOrDefault if no throw is wanted.
395 *
396 * ```js
397 * from([2, 1, 5]).last(x => x < 4)
398 * // => 1
399 * from([]).last(x => x < 0)
400 * // => throws
401 * ```
402 */
403 last(predicate: (arg: T) => any): T;
404 /** Get the last element in the sequence. If empty, returns undefined.
405 *
406 * ```js
407 * from([2, 1, 5]).lastOrDefault()
408 * // => 5
409 * from([]).lastOrDefault()
410 * // => undefined
411 * ```
412 */
413 lastOrDefault(): T | undefined;
414 /** Get the last element in the sequence that matches a condition. If empty or no matches, returns undefined.
415 *
416 * ```js
417 * from([2, 1, 5]).lastOrDefault(x => x < 4)
418 * // => 1
419 * from([2, 1, 5]).lastOrDefault(x => x < 0)
420 * // => undefined
421 * ```
422 */
423 lastOrDefault(predicate: (arg: T) => any): T | undefined;
424 /** True if all elements pass the predicate
425 *
426 * ```js
427 * from([2, 1, 5]).all(x => x >= 1)
428 * // => true
429 * from([2, 1, 5]).all(x => x >= 2)
430 * // => false
431 * ```
432 */
433 all(predicate: (arg: T) => any): boolean;
434 /** True if any elements pass the predicate
435 *
436 * ```js
437 * from([2, 1, 5]).any(x => x >= 4)
438 * // => true
439 * from([2, 1, 5]).any(x => x <= 0)
440 * // => false
441 * ```
442 */
443 any(predicate: (arg: T) => any): boolean;
444 /** True if the sequence is not empty
445 *
446 * ```js
447 * from([2, 1, 5]).any()
448 * // => true
449 * from([]).any()
450 * // => false
451 * ```
452 */
453 any(): boolean;
454 /** True if no elements pass the predicate
455 *
456 * ```js
457 * from([2, 1, 5]).none(x => x === 0)
458 * // => true
459 * from([2, 1, 5]).none(x => x === 1)
460 * // => false
461 * ```
462 */
463 none(predicate: (arg: T) => any): boolean;
464 /** True if the element is in the sequence. Checked with ===.
465 *
466 * ```js
467 * from([2, 1, 5]).contains(1)
468 * // => true
469 * from([{ a: '1' }]).contains({ a: '1' })
470 * // => false (strict equality. use any with a custom search instead.)
471 * ```
472 */
473 contains(value: T): boolean;
474 /** Projects each element to a number and sums the sequence. If empty, returns 0.
475 *
476 * ```js
477 * from(['2', '1', '5']).sum(x => parseFloat(x))
478 * // => 8
479 * ```
480 */
481 sum(f: (arg: T) => number): number;
482 /** Projects each element to a number and averages the sequence. If empty, throws.
483 *
484 * ```js
485 * from(['2', '1', '6']).average(x => parseFloat(x))
486 * // => 3
487 * ```
488 */
489 average(f: (arg: T) => number): number;
490 /** Projects each element to a number and finds the max of the sequence. If empty, throws.
491 *
492 * ```js
493 * from(['2', '1', '5']).max(x => parseFloat(x))
494 * // => 5
495 * ```
496 */
497 max(f: (arg: T) => number): number;
498 /** Projects each element to a number and finds the min of the sequence. If empty, throws.
499 *
500 * ```js
501 * from(['2', '1', '5']).min(x => parseFloat(x))
502 * // => 1
503 * ```
504 */
505 min(f: (arg: T) => number): number;
506 /** Finds the minimum element in the sequence according to a selector. Equivalent (but faster) to orderBy(f).first().
507 *
508 * ```js
509 * from([{ key: 'A', value: 2 }, { key: 'B', value: 1 }, { key: 'C', value: 10 }]).minBy(x => x.value)
510 * // => { key: 'B', value: 1 }
511 * ```
512 */
513 minBy(f: (arg: T) => number): T;
514 /** Finds the maximum element in the sequence according to a selector. Equivalent (but faster) to orderByDescending(f).first().
515 *
516 * ```js
517 * from([{ key: 'A', value: 2 }, { key: 'B', value: 1 }, { key: 'C', value: 10 }]).maxBy(x => x.value)
518 * // => { key: 'C', value: 10 }
519 * ```
520 */
521 maxBy(f: (arg: T) => number): T;
522 /** Iterates through this sequence. */
523 [Symbol.iterator](): Iterator<T>;
524}
525/** A sequence of numbers */
526export interface NumberSequence<T> extends AnySequence<T> {
527 /** Sums every number in the sequence. If empty, returns 0.
528 *
529 * ```js
530 * from([2, 1, 5]).sum()
531 * // => 8
532 * ```
533 */
534 sum(): number;
535 /** Averages the sequence. If empty, throws.
536 *
537 * ```js
538 * from([2, 1, 6]).average()
539 * // => 3
540 * ```
541 */
542 average(): number;
543 /** Finds the maximum in the sequence. If empty, throws.
544 *
545 * ```js
546 * from([2, 1, 5]).max()
547 * // => 5
548 * ```
549 */
550 max(): number;
551 /** Finds the minimum in the sequence. If empty, throws.
552 *
553 * ```js
554 * from([2, 1, 5]).min()
555 * // => 1
556 * ```
557 */
558 min(): number;
559}
560declare type UnwrapIterable<T> = [T] extends [Iterable<infer U>] ? U : never;
561/** A sequence of iterable elements */
562export interface ArraySequence<T> extends AnySequence<T> {
563 /** Project each element to an iterable/array, then flatten the result
564 *
565 * ```js
566 * from([[1, 2], [3, 4]]).flat(x => [...x, 0])
567 * // => [1, 2, 0, 3, 4, 0]
568 * ```
569 */
570 flat<TProject>(projector: (input: T) => Iterable<TProject>): Sequence<TProject>;
571 /** Flatten the sequence
572 *
573 * ```js
574 * from([[1, 2], [3, 4]]).flat()
575 * // => [1, 2, 3, 4]
576 * ```
577 */
578 flat(): Sequence<UnwrapIterable<T>>;
579}
580/** A sequence of strings */
581export interface StringSequence<T> extends AnySequence<T> {
582 /** Joins the elements with an optional separator
583 *
584 * ```js
585 * from(['a', 'b', 'c']).joinString(', ')
586 * // => 'a, b, c'
587 * ```
588 */
589 joinString(separator?: string): string;
590}
591export interface WithKey<TKey> {
592 /** The key that this set was grouped by */
593 readonly key: TKey;
594}
595export interface WithOrderedMethods<T> {
596 /** Order the sequence by another key, ascending.
597 *
598 * ```js
599 * // Sort by length of the string, then alphabetical order
600 * from(['two', 'one', 'thirteen', 'five']).orderBy(x => x.length).thenBy(x => x)
601 * // => ['one', 'two', 'five', 'thirteen']
602 * ```
603 */
604 thenBy(keySelector: (arg: T) => string | number): OrderedSequence<T>;
605 /** Order the sequence by another key, ascending, with a custom comparer.
606 *
607 * See orderBy for an example.
608 */
609 thenBy<TKey>(keySelector: (arg: T) => TKey, comparer: ICompare<TKey>): OrderedSequence<T>;
610 /** Order the sequence by another key, descending.
611 *
612 * ```js
613 * // Sort by length of the string, then reverse alphabetical order
614 * from(['one', 'two', 'thirteen', 'five']).orderBy(x => x.length).thenByDescending(x => x)
615 * // => ['two', 'one', 'five', 'thirteen']
616 * ```
617 */
618 thenByDescending(keySelector: (arg: T) => string | number): OrderedSequence<T>;
619 /** Order the sequence by another key, descending, with a custom comparer.
620 *
621 *
622 * See orderBy for an example.
623 */
624 thenByDescending<TKey>(keySelector: (arg: T) => TKey, comparer: ICompare<TKey>): OrderedSequence<T>;
625}
626declare type DoesExtend<T, TWant> = [T] extends [TWant] ? T : never;
627declare type DoesExtendAny<T> = any extends T ? never : T;
628declare type ExtendsCarefully<T, TWant> = DoesExtendAny<DoesExtend<T, TWant>>;
629/** A sequence of values. */
630export declare type Sequence<T> = ExtendsCarefully<T, number> extends never ? (ExtendsCarefully<T, string> extends never ? (ExtendsCarefully<T, Iterable<unknown>> extends never ? AnySequence<T> : ArraySequence<T>) : StringSequence<T>) : NumberSequence<T>;
631/** A sequence with a key. Obtained from groupBy. */
632export declare type KeySequence<TKey, TElement> = WithKey<TKey> & Sequence<TElement>;
633/** An ordered sequence. Can use thenBy to continue ordering. */
634export declare type OrderedSequence<T> = WithOrderedMethods<T> & Sequence<T>;
635/** Gets the sequence type.
636 * ```typescript
637 * type MySequence = Sequence<string>
638 * type MySequenceType = SequenceType<MySequence>
639 * // MySequenceType === string
640 * ```
641 */
642export declare type SequenceType<T> = T extends Sequence<infer Y> ? Y : never;
643/** Compares two values.
644 * If a comes before b, the result should be negative.
645 * If both values are equal, the result should be zero.
646 * If a comes after b, the result should be positive.
647 */
648export declare type ICompare<T> = (a: T, b: T) => number;
649/** Start the sequence. Can be used with an array or any iterable.
650 *
651 * ```js
652 * // Import me:
653 * import from from '@adamburgess/linq'
654 * // Arrays:
655 * from([1, 2, 3])
656 * // Objects that support the Iterable protocol:
657 * from(new Map())
658 * // Generators:
659 * from(function*() { yield 'generated values' })
660 * ```
661*/
662export declare function from<T>(it: Iterable<T>): Sequence<T>;
663export default from;
664
\No newline at end of file