Lodash: Add missing use cases#20795
Lodash: Add missing use cases#20795DanielRosenwasser merged 12 commits intoDefinitelyTyped:masterfrom
Conversation
|
types/lodash/index.d.ts to authors (@bczengel @chrootsu @stepancar @ericanderson @Ailrun @e-cloud). Could you review this PR? |
|
@aj-r Please address comments from the code reviewers. |
|
Note that this problem also affects |
Comparators should accept any truthy/falsy value, not just true/false. Functions affected: differenceWith, intersectionBy, intersectionWith, pullAllBy, pullAllwith
|
@Andy-MS Any idea how to fix the GC error in Travis? I get the same error when running |
|
Looks like we've fixed some bugs since ts2.3. Also, tests will fail in ts2.3 because type inference has been improved. (I don't run out of memory when just running |
|
@bczengel @chrootsu @stepancar @ericanderson @Ailrun @e-cloud Checks are now passing. Could you review this PR? |
|
I guess @thorn0 could also review this, since he's an author now. |
|
Reverting the changes one by one and repeatedly running lint, you can find what breaks TS 2.3. That's what I did with my PR. |
types/lodash/index.d.ts
Outdated
| type ValueKeyIteratee<T> = ((value: T, key: string) => any) | string | [string, any] | PartialDeep<T>; | ||
| type Comparator<T> = (a: T, b: T) => boolean; | ||
| type Comparator<T> = (a: T, b: T) => any; | ||
| type Comparator2<T1, T2> = (a: T1, b: T2) => any; |
There was a problem hiding this comment.
Why the return type is any?
There was a problem hiding this comment.
Lodash looks for any truthy or falsy value in the return value, so we shouldn't restrict it to just booleans. For example, see this comparator: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/20795/files#diff-6a82a43b7b79f07644334583c1add52aR671. boolean | undefined should be an allowed return type because lodash will treat undefined as a falsy value.
There was a problem hiding this comment.
I don't buy that logic -- if something will be treated as a boolean it should be typed as a boolean. Math.abs("-2") will work at runtime but isn't allowed by TypeScript.
There was a problem hiding this comment.
Returning a non-boolean value in callbacks is a common use case that people have opened issues for in the past - see #18956. If we force a boolean return value in comparators, then for consistency I think we should also force boolean return values in functions like filter, some, and every. But that would break #18956.
There was a problem hiding this comment.
Let's break it. TypeScript's philosophy in regard to this kind of forgiveness and implicit conversions seems to be clear and simple.
There was a problem hiding this comment.
What if we allow the return type to be boolean | null | undefined? That would support the use case in #18956, but also prevent the user from returning bad things like strings, objects, or functions.
There was a problem hiding this comment.
Then again, maybe it's not a big deal to force users to put !! in front of anything that would otherwise be undefined.
There was a problem hiding this comment.
boolean | null | undefined looks like a good trade-off. In particular, there will still be an error if the user forgets to return a value (x => x vs x => { x }) due to the fact that TS makes a distinction between undefined and void.
There was a problem hiding this comment.
In Java and the like, even conditions in if statements must be of boolean type, which was considered a step forward to type safety. Everyone seems to have been okay with this design decision.
There was a problem hiding this comment.
This made me think, what if we change the type of ValueIteratee for functions like differenceBy from the current shape (value: T) => any to (value: T) => {} | undefined | null. If I'm not mistaken, {} | undefined | null means "any except void". And an iteratee callback that never returns a value is definitely a mistake.
types/lodash/index.d.ts
Outdated
| iteratee: object | ||
| ): boolean[]; | ||
| } | ||
| type T234 = number[][0]; |
There was a problem hiding this comment.
Looks like debug leftovers.
types/lodash/index.d.ts
Outdated
| type ValueKeyIteratee<T> = ((value: T, key: string) => any) | string | [string, any] | PartialDeep<T>; | ||
| type Comparator<T> = (a: T, b: T) => boolean; | ||
| type Comparator<T> = (a: T, b: T) => any; | ||
| type Comparator2<T1, T2> = (a: T1, b: T2) => any; |
There was a problem hiding this comment.
Let's break it. TypeScript's philosophy in regard to this kind of forgiveness and implicit conversions seems to be clear and simple.
|
The rest of the PR looks good. Also you were going to fix |
|
Looks like someone else is fixing |
|
I've discovered that if you run:
instead of:
then it will tell you the actual errors, instead of giving you the GC error. |
|
@thorn0 I have updated based on your comments. Please review again. |
|
Great. Let's introduce an alias for |
|
@thorn0 done |
|
Approved by a listed owner. PR ready to merge pending express review by a maintainer. |
|
👎 for |
rbuckton
left a comment
There was a problem hiding this comment.
I'm concerned about the loss of type safety introduced with Comparator2 and the changes to the type parameters in many of the methods.
| values?: List<T>, | ||
| comparator?: Comparator<T> | ||
| ): T[]; | ||
| differenceWith<T1, T2>( |
There was a problem hiding this comment.
This seems like an odd choice if T1 and T2 are not comparable (e.g. when comparator is undefined). I would recommend you leave the original overload and add this one with both values and comparator as required, otherwise the entire method is much less type safe.
|
@aj-r Please fix the failures indicated in the Travis CI log. |
|
Approved by a listed owner. PR ready to merge pending express review by a maintainer. |
|
@rbuckton - Thanks for your review of this PR! Can you please look at the new code and update your review status if appropriate? |
|
@rbuckton Can you review this again now that I have made your requested changes? |
|
@rbuckton - Thanks for your review of this PR! Can you please look at the new code and update your review status if appropriate? |
|
Thanks for being patient! |
Fixes #20741. I've added support for some subtle use cases that broke with #19356, specifically for
differenceByandflatMap.For the context of these changes, see:
Please fill in this template.
npm run lint package-name(ortscif notslint.jsonis present).If changing an existing definition:
tslint.jsoncontaining{ "extends": "dtslint/dt.json" }. (already exists)