feat(stdlib): new modules + eslint/tsconfig migration
- Add array/async/etc. modules and type tests; migrate to eslint flat config and composite tsconfig (vitest typecheck enabled). - Fix PubSub.emit to snapshot listeners before iterating (stable EventEmitter semantics; avoids invoking listeners added during the same emit).
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import { describe, expectTypeOf, it } from 'vitest';
|
||||
import { partition } from '.';
|
||||
|
||||
describe('partition', () => {
|
||||
it('returns a tuple of two arrays of the element type', () => {
|
||||
const result = partition([1, 2, 3], n => n > 1);
|
||||
|
||||
expectTypeOf(result).toEqualTypeOf<[number[], number[]]>();
|
||||
});
|
||||
|
||||
it('narrows both partitions with a type guard', () => {
|
||||
const mixed: Array<string | number> = ['a', 1];
|
||||
const result = partition(mixed, (v): v is string => typeof v === 'string');
|
||||
|
||||
expectTypeOf(result).toEqualTypeOf<[string[], number[]]>();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { partition } from '.';
|
||||
|
||||
describe('partition', () => {
|
||||
it('split by a predicate into [matching, rest]', () => {
|
||||
expect(partition([1, 2, 3, 4], n => n % 2 === 0)).toEqual([[2, 4], [1, 3]]);
|
||||
});
|
||||
|
||||
it('preserve order within each partition', () => {
|
||||
expect(partition([5, 1, 4, 2, 3], n => n > 2)).toEqual([[5, 4, 3], [1, 2]]);
|
||||
});
|
||||
|
||||
it('pass the index to the predicate', () => {
|
||||
expect(partition(['a', 'b', 'c', 'd'], (_, i) => i < 2)).toEqual([['a', 'b'], ['c', 'd']]);
|
||||
});
|
||||
|
||||
it('handle all-matching and none-matching', () => {
|
||||
expect(partition([1, 2, 3], () => true)).toEqual([[1, 2, 3], []]);
|
||||
expect(partition([1, 2, 3], () => false)).toEqual([[], [1, 2, 3]]);
|
||||
});
|
||||
|
||||
it('work with a type guard', () => {
|
||||
const mixed: Array<string | number> = ['a', 1, 'b', 2];
|
||||
const [strings, numbers] = partition(mixed, (v): v is string => typeof v === 'string');
|
||||
|
||||
expect(strings).toEqual(['a', 'b']);
|
||||
expect(numbers).toEqual([1, 2]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @name partition
|
||||
* @category Arrays
|
||||
* @description Splits an array into two: elements that satisfy the predicate and those that do not
|
||||
*
|
||||
* @param {Value[]} array - The array to split
|
||||
* @param {(item: Value, index: number) => boolean} predicate - Decides which partition an element belongs to
|
||||
* @returns {[Value[], Value[]]} A tuple of `[matching, rest]`
|
||||
*
|
||||
* @example
|
||||
* partition([1, 2, 3, 4], n => n % 2 === 0) // => [[2, 4], [1, 3]]
|
||||
*
|
||||
* @example
|
||||
* const [strings, others] = partition(mixed, (v): v is string => typeof v === 'string');
|
||||
*
|
||||
* @since 0.0.10
|
||||
*/
|
||||
export function partition<Value, Matched extends Value>(
|
||||
array: Value[],
|
||||
predicate: (item: Value, index: number) => item is Matched,
|
||||
): [Matched[], Array<Exclude<Value, Matched>>];
|
||||
export function partition<Value>(
|
||||
array: Value[],
|
||||
predicate: (item: Value, index: number) => boolean,
|
||||
): [Value[], Value[]];
|
||||
export function partition<Value>(
|
||||
array: Value[],
|
||||
predicate: (item: Value, index: number) => boolean,
|
||||
): [Value[], Value[]] {
|
||||
const matched: Value[] = [];
|
||||
const rest: Value[] = [];
|
||||
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const item = array[i]!;
|
||||
|
||||
if (predicate(item, i))
|
||||
matched.push(item);
|
||||
else
|
||||
rest.push(item);
|
||||
}
|
||||
|
||||
return [matched, rest];
|
||||
}
|
||||
Reference in New Issue
Block a user