ramda: Workaround for type inference problem in Filter (#28592)

* ramda: add return type assertions for filter/reject test

* ramda: Add failing test for filter-in-pipe scenario

* ramda: Workaround for type inference problem in Filter

In the `Filter` type, when used inside a pipe, the second format always took
precedence in type inference, causing problems when a list was filtered.

With this change, you can manually specify whether you are using filter
for an array or an object, so usage in a pipe will work. You can also
leave out the second type parameter, in which case filter works as
previously.

```ts
import { pipe, filter } from 'ramda';

pipe(
    filter<string, 'array'>((val: string) => val.length > 2),
)(['list', 'or', 'object']);

pipe(
    filter<string, 'object'>((val) => val.length > 2),
)({ a: 'list', b: 'or', c: 'object' });
```
This commit is contained in:
Miika Hänninen
2018-10-02 11:34:46 -07:00
committed by Wesley Wigham
parent 6ae761686a
commit b8b95c0cf8
2 changed files with 39 additions and 13 deletions
+13 -9
View File
@@ -80,9 +80,17 @@ declare namespace R {
set<T, U>(str: string, obj: T): U;
}
interface Filter<T> {
(list: ReadonlyArray<T>): T[];
(obj: Dictionary<T>): Dictionary<T>;
interface Filter {
<T>(fn: (value: T) => boolean): FilterOnceApplied<T>;
<T, Kind extends 'array'>(fn: (value: T) => boolean): (list: ReadonlyArray<T>) => T[];
<T, Kind extends 'object'>(fn: (value: T) => boolean): (list: Dictionary<T>) => Dictionary<T>;
<T>(fn: (value: T) => boolean, list: ReadonlyArray<T>): T[];
<T>(fn: (value: T) => boolean, obj: Dictionary<T>): Dictionary<T>;
}
interface FilterOnceApplied<T> {
(list: ReadonlyArray<T>): T[];
(obj: Dictionary<T>): Dictionary<T>;
}
type Evolve<O extends Evolvable<E>, E extends Evolver> = {
@@ -721,9 +729,7 @@ declare namespace R {
/**
* Returns a new list containing only those items that match a given predicate function. The predicate function is passed one argument: (value).
*/
filter<T>(fn: (value: T) => boolean): Filter<T>;
filter<T>(fn: (value: T) => boolean, list: ReadonlyArray<T>): T[];
filter<T>(fn: (value: T) => boolean, obj: Dictionary<T>): Dictionary<T>;
filter: Filter;
/**
* Returns the first element of the list which matches the predicate, or `undefined` if no
@@ -1906,9 +1912,7 @@ declare namespace R {
* Similar to `filter`, except that it keeps only values for which the given predicate
* function returns falsy.
*/
reject<T>(fn: (value: T) => boolean): Filter<T>;
reject<T>(fn: (value: T) => boolean, list: ReadonlyArray<T>): T[];
reject<T>(fn: (value: T) => boolean, obj: Dictionary<T>): Dictionary<T>;
reject: Filter;
/**
* Removes the sub-list of `list` starting at index `start` and containing `count` elements.
+26 -4
View File
@@ -695,12 +695,34 @@ R.times(i, 5);
}
const filterEven = R.filter(isEven);
filterEven({ a: 0, b: 1 }); // => { a: 0 }
filterEven([0, 1]); // => [0]
const objA: R.Dictionary<number> = filterEven({ a: 0, b: 1 }); // => { a: 0 }
const listA: number[] = filterEven([0, 1]); // => [0]
const rejectEven = R.reject(isEven);
rejectEven({ a: 0, b: 1 }); // => { b: 1 }
rejectEven([0, 1]); // => [1]
const objB: R.Dictionary<number> = rejectEven({ a: 0, b: 1 }); // => { b: 1 }
const listB: number[] = rejectEven([0, 1]); // => [1]
};
() => {
function isEven(n: number) {
return n % 2 === 0;
}
const a: R.Dictionary<number> = R.pipe(
R.filter<number, 'object'>(isEven),
)({ a: 0, b: 1 }); // => { a: 0 }
const b: number[] = R.pipe(
R.filter<number, 'array'>(isEven),
)([0, 1]); // => [0]
const c: R.Dictionary<number> = R.pipe(
R.reject<number, 'object'>(isEven),
)({ a: 0, b: 1 }); // => { b: 1 }
const d: number[] = R.pipe(
R.reject<number, 'array'>(isEven),
)([0, 1]); // => [1]
};
() => {