Skip to content

Lodash: Add missing use cases#20795

Merged
DanielRosenwasser merged 12 commits intoDefinitelyTyped:masterfrom
aj-r:add-use-cases
Nov 11, 2017
Merged

Lodash: Add missing use cases#20795
DanielRosenwasser merged 12 commits intoDefinitelyTyped:masterfrom
aj-r:add-use-cases

Conversation

@aj-r
Copy link
Contributor

@aj-r aj-r commented Oct 21, 2017

Fixes #20741. I've added support for some subtle use cases that broke with #19356, specifically for differenceBy and flatMap.

For the context of these changes, see:

Please fill in this template.

  • Use a meaningful title for the pull request. Include the name of the package modified.
  • Test the change in your own code. (Compile and run.)
  • Follow the advice from the readme.
  • Avoid common mistakes.
  • Run npm run lint package-name (or tsc if no tslint.json is present).

If changing an existing definition:

@dt-bot
Copy link
Member

dt-bot commented Oct 21, 2017

types/lodash/index.d.ts

to authors (@bczengel @chrootsu @stepancar @ericanderson @Ailrun @e-cloud). Could you review this PR?
👍 or 👎?

@typescript-bot typescript-bot added Popular package This PR affects a popular package (as counted by NPM download counts). The Travis CI build failed labels Oct 21, 2017
@typescript-bot
Copy link
Contributor

typescript-bot commented Oct 21, 2017

@aj-r Please address comments from the code reviewers.

@sheetalkamat sheetalkamat added the Has Merge Conflict This PR can't be merged because it has a merge conflict. The author needs to update it. label Oct 23, 2017
@typescript-bot typescript-bot removed the Has Merge Conflict This PR can't be merged because it has a merge conflict. The author needs to update it. label Oct 23, 2017
@karptonite
Copy link

Note that this problem also affects differenceWith, perhaps even more, since differenceWith takes a callback, and there is no reason to think that the callback couldn't take different types for the first and second arguments.

aj-r added 2 commits October 24, 2017 21:36
Comparators should accept any truthy/falsy value, not just true/false.
Functions affected: differenceWith, intersectionBy, intersectionWith, pullAllBy, pullAllwith
@aj-r
Copy link
Contributor Author

aj-r commented Oct 25, 2017

@Andy-MS Any idea how to fix the GC error in Travis? I get the same error when running npm run lint lodash locally but have no idea how to fix it. It always happens when testing with TS 2.3.

@ghost
Copy link

ghost commented Oct 25, 2017

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 tsc on the command line.) You could just specify // TypeScript Version: 2.4 in the header.

@aj-r
Copy link
Contributor Author

aj-r commented Oct 26, 2017

@bczengel @chrootsu @stepancar @ericanderson @Ailrun @e-cloud Checks are now passing. Could you review this PR?

@aj-r
Copy link
Contributor Author

aj-r commented Oct 26, 2017

I guess @thorn0 could also review this, since he's an author now.

@thorn0
Copy link
Contributor

thorn0 commented Oct 26, 2017

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.

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the return type is any?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's break it. TypeScript's philosophy in regard to this kind of forgiveness and implicit conversions seems to be clear and simple.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then again, maybe it's not a big deal to force users to put !! in front of anything that would otherwise be undefined.

Copy link
Contributor

@thorn0 thorn0 Oct 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

@thorn0 thorn0 Oct 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

iteratee: object
): boolean[];
}
type T234 = number[][0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like debug leftovers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, Thanks!

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's break it. TypeScript's philosophy in regard to this kind of forgiveness and implicit conversions seems to be clear and simple.

@thorn0
Copy link
Contributor

thorn0 commented Oct 27, 2017

The rest of the PR looks good. Also you were going to fix isFunction, weren't you?

@aj-r
Copy link
Contributor Author

aj-r commented Oct 28, 2017

Looks like someone else is fixing isFunction: #21015

@aj-r
Copy link
Contributor Author

aj-r commented Oct 28, 2017

I've discovered that if you run:

node node_modules\dtslint\bin\index.js types lodash

instead of:

npm run lint lodash

then it will tell you the actual errors, instead of giving you the GC error.

@aj-r
Copy link
Contributor Author

aj-r commented Oct 28, 2017

@thorn0 I have updated based on your comments. Please review again.

@thorn0
Copy link
Contributor

thorn0 commented Oct 28, 2017

Great. Let's introduce an alias for boolean | null | undefined. How about Boolish?

@aj-r
Copy link
Contributor Author

aj-r commented Oct 29, 2017

@thorn0 done

@typescript-bot
Copy link
Contributor

Approved by a listed owner. PR ready to merge pending express review by a maintainer.

@ghost
Copy link

ghost commented Oct 30, 2017

👎 for boolean | null | undefined , since the actual function does not look for null | undefined values -- it just treats the input as a boolean. Users who don't want to deal with nullness errors yet could just disable --strictNullChecks.

Copy link
Collaborator

@rbuckton rbuckton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@typescript-bot typescript-bot added Revision needed This PR needs code changes before it can be merged. and removed Merge:Express labels Oct 31, 2017
@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Oct 31, 2017

@aj-r Please fix the failures indicated in the Travis CI log.

@RyanCavanaugh RyanCavanaugh added The Travis CI build failed and removed Revision needed This PR needs code changes before it can be merged. labels Nov 1, 2017
@RyanCavanaugh
Copy link
Member

Approved by a listed owner. PR ready to merge pending express review by a maintainer.

@RyanCavanaugh
Copy link
Member

@rbuckton - Thanks for your review of this PR! Can you please look at the new code and update your review status if appropriate?

@aj-r
Copy link
Contributor Author

aj-r commented Nov 10, 2017

@rbuckton Can you review this again now that I have made your requested changes?

@typescript-bot
Copy link
Contributor

@rbuckton - Thanks for your review of this PR! Can you please look at the new code and update your review status if appropriate?

@DanielRosenwasser DanielRosenwasser merged commit 67f4cca into DefinitelyTyped:master Nov 11, 2017
@DanielRosenwasser
Copy link
Member

Thanks for being patient!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Popular package This PR affects a popular package (as counted by NPM download counts).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants