Skip to content

Commit

Permalink
feat(micro-dash): improve typing of reduce() and reduceRight()
Browse files Browse the repository at this point in the history
Closes #20
  • Loading branch information
ersimont committed Jan 7, 2021
1 parent c0aa75e commit 6c5500d
Show file tree
Hide file tree
Showing 6 changed files with 350 additions and 29 deletions.
7 changes: 6 additions & 1 deletion projects/micro-dash/src/lib/collection/reduce-right.spec.ts
Expand Up @@ -5,7 +5,12 @@ import { reduceRight } from './reduce-right';
describe('reduceRight()', () => {
it('works with `undefined`', () => {
expect(reduceRight(undefined, () => 1, 2)).toEqual(2);
expect(reduceRight(undefined, () => 1)).toBeUndefined();
expect(reduceRight(undefined as any, () => 1)).toBeUndefined();
});

it('works with `null`', () => {
expect(reduceRight(null, () => 1, 2)).toEqual(2);
expect(reduceRight(null as any, () => 1)).toBeUndefined();
});

//
Expand Down
39 changes: 26 additions & 13 deletions projects/micro-dash/src/lib/collection/reduce-right.ts
@@ -1,4 +1,4 @@
import { ObjectWith } from '../interfaces';
import { IfCouldBe, Nil } from '../interfaces';
import { forEachRight } from './for-each-right';
import { doReduce } from './reduce-utils';

Expand All @@ -9,22 +9,35 @@ import { doReduce } from './reduce-utils';
* - Lodash: 14,053 bytes
* - Micro-dash: 357 bytes
*/
export function reduceRight<E>(
array: E[] | undefined,
iteratee: (accumulator: E, value: E, index: number) => E,
): E;

export function reduceRight<T extends any[] | Nil>(
array: T,
iteratee: (
accumulator: NonNullable<T>[number],
value: NonNullable<T>[number],
index: number,
) => NonNullable<T>[number],
): NonNullable<T>[number] | IfCouldBe<T, Nil, undefined>;
export function reduceRight<E, A>(
array: E[] | undefined,
array: E[] | Nil,
iteratee: (accumulator: A, value: E, index: number) => A,
accumulator: A,
): A;
export function reduceRight<E>(
array: ObjectWith<E> | undefined,
iteratee: (accumulator: E, value: E, key: keyof E) => E,
): E;
export function reduceRight<E, A>(
array: ObjectWith<E> | undefined,
iteratee: (accumulator: A, value: E, key: keyof E) => A,
export function reduceRight<T>(
object: T,
iteratee: (
accumulator: NonNullable<T>[keyof NonNullable<T>],
value: NonNullable<T>[keyof NonNullable<T>],
key: keyof NonNullable<T>,
) => NonNullable<T>[keyof NonNullable<T>],
): NonNullable<T>[keyof NonNullable<T>] | IfCouldBe<T, Nil, undefined>;
export function reduceRight<T, A>(
object: T,
iteratee: (
accumulator: A,
value: NonNullable<T>[keyof NonNullable<T>],
key: keyof NonNullable<T>,
) => A,
accumulator: A,
): A;

Expand Down
7 changes: 6 additions & 1 deletion projects/micro-dash/src/lib/collection/reduce.spec.ts
Expand Up @@ -5,7 +5,12 @@ import { reduce } from './reduce';
describe('reduce()', () => {
it('works with `undefined`', () => {
expect(reduce(undefined, () => 1, 2)).toEqual(2);
expect(reduce(undefined, () => 1)).toBeUndefined();
expect(reduce(undefined as any, () => 1)).toBeUndefined();
});

it('works with `null`', () => {
expect(reduce(null, () => 1, 2)).toEqual(2);
expect(reduce(null as any, () => 1)).toBeUndefined();
});

//
Expand Down
42 changes: 28 additions & 14 deletions projects/micro-dash/src/lib/collection/reduce.ts
@@ -1,4 +1,4 @@
import { ObjectWith } from '../interfaces';
import { IfCouldBe, Nil } from '../interfaces';
import { forEach } from './for-each';
import { doReduce } from './reduce-utils';

Expand All @@ -9,24 +9,38 @@ import { doReduce } from './reduce-utils';
* - Lodash: 14,074 bytes
* - Micro-dash: 361 bytes
*/
export function reduce<E>(
array: E[] | undefined,
iteratee: (accumulator: E, value: E, index: number) => E,
): E;

export function reduce<T extends any[] | Nil>(
array: T,
iteratee: (
accumulator: NonNullable<T>[number],
value: NonNullable<T>[number],
index: number,
) => NonNullable<T>[number],
): NonNullable<T>[number] | IfCouldBe<T, Nil, undefined>;
export function reduce<E, A>(
array: E[] | undefined,
array: E[] | Nil,
iteratee: (accumulator: A, value: E, index: number) => A,
accumulator?: A,
accumulator: A,
): A;
export function reduce<E>(
array: ObjectWith<E> | undefined,
iteratee: (accumulator: E, value: E, key: keyof E) => E,
): E;
export function reduce<E, A>(
array: ObjectWith<E> | undefined,
iteratee: (accumulator: A, value: E, key: keyof E) => A,
export function reduce<T>(
object: T,
iteratee: (
accumulator: NonNullable<T>[keyof NonNullable<T>],
value: NonNullable<T>[keyof NonNullable<T>],
key: keyof NonNullable<T>,
) => NonNullable<T>[keyof NonNullable<T>],
): NonNullable<T>[keyof NonNullable<T>] | IfCouldBe<T, Nil, undefined>;
export function reduce<T, A>(
object: T,
iteratee: (
accumulator: A,
value: NonNullable<T>[keyof NonNullable<T>],
key: keyof NonNullable<T>,
) => A,
accumulator: A,
): A;

export function reduce(collection: any, iteratee: any, accumulator?: any): any {
return doReduce(
forEach,
Expand Down
@@ -0,0 +1,142 @@
import { reduceRight } from '../../lib/collection';
import { identity } from '../../lib/util';

type Ary = Array<string | number>;
type Obj = { a: string; b: number };

declare const a: Ary;
declare const aOrNull: Ary | null;
declare const aOrUndefined: Ary | undefined;
declare const aOrNullOrUndefined: Ary | null | undefined;
declare const o: Obj;
declare const oOrNull: Obj | null;
declare const oOrUndefined: Obj | undefined;
declare const oOrNullOrUndefined: Obj | null | undefined;

// $ExpectType string | number
reduceRight(a, identity);
// $ExpectType string | number | undefined
reduceRight(aOrNull, identity);
// $ExpectType string | number | undefined
reduceRight(aOrUndefined, identity);
// $ExpectType string | number | undefined
reduceRight(aOrNullOrUndefined, identity);
// $ExpectType number
reduceRight(a, identity, 4);
// $ExpectType number
reduceRight(aOrNull, identity, 4);
// $ExpectType number
reduceRight(aOrUndefined, identity, 4);
// $ExpectType number
reduceRight(aOrNullOrUndefined, identity, 4);

// $ExpectType string | number
reduceRight(o, identity);
// $ExpectType string | number | undefined
reduceRight(oOrNull, identity);
// $ExpectType string | number | undefined
reduceRight(oOrUndefined, identity);
// $ExpectType string | number | undefined
reduceRight(oOrNullOrUndefined, identity);
// $ExpectType number
reduceRight(o, identity, 4);
// $ExpectType number
reduceRight(oOrNull, identity, 4);
// $ExpectType number
reduceRight(oOrUndefined, identity, 4);
// $ExpectType number
reduceRight(oOrNullOrUndefined, identity, 4);

reduceRight(
a,
(
// $ExpectType string | number
accumulator,
// $ExpectType string | number
value,
// $ExpectType number
index,
) => 1,
);
reduceRight(
aOrNull,
(
// $ExpectType string | number
accumulator,
// $ExpectType string | number
value,
// $ExpectType number
index,
) => 1,
);
reduceRight(
a,
(
// $ExpectType Date
accumulator,
// $ExpectType string | number
value,
// $ExpectType number
index,
) => accumulator,
new Date(),
);
reduceRight(
aOrNull,
(
// $ExpectType Date
accumulator,
// $ExpectType string | number
value,
// $ExpectType number
index,
) => accumulator,
new Date(),
);

reduceRight(
o,
(
// $ExpectType string | number
accumulator,
// $ExpectType string | number
value,
// $ExpectType "a" | "b"
index,
) => 1,
);
reduceRight(
oOrNull,
(
// $ExpectType string | number
accumulator,
// $ExpectType string | number
value,
// $ExpectType "a" | "b"
index,
) => 1,
);
reduceRight(
o,
(
// $ExpectType Date
accumulator,
// $ExpectType string | number
value,
// $ExpectType "a" | "b"
index,
) => accumulator,
new Date(),
);
reduceRight(
oOrNull,
(
// $ExpectType Date
accumulator,
// $ExpectType string | number
value,
// $ExpectType "a" | "b"
index,
) => accumulator,
new Date(),
);

0 comments on commit 6c5500d

Please sign in to comment.