Skip to content

[Ramda]: fixed pick and omit type signatures to reflect projections#24936

Merged
RyanCavanaugh merged 7 commits intoDefinitelyTyped:masterfrom
ProofOfKeags:feature/pick-omit-type-correctness
Apr 17, 2018
Merged

[Ramda]: fixed pick and omit type signatures to reflect projections#24936
RyanCavanaugh merged 7 commits intoDefinitelyTyped:masterfrom
ProofOfKeags:feature/pick-omit-type-correctness

Conversation

@ProofOfKeags
Copy link
Contributor

@ProofOfKeags ProofOfKeags commented Apr 12, 2018

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.)
  • Add or edit tests to reflect the change. (Run with npm test.)
  • Follow the advice from the readme.
  • Avoid common mistakes.
  • [x*] Run npm run lint package-name (or tsc if no tslint.json is present).

*NOTE: There are unrelated linting/compile errors in this module that have arisen due to typescript@next. I can include fixes for them in this PR if you would like but I figured I'd keep it separate as to not clutter what was being changed with this PR.

Select one of these and delete the others:

If changing an existing definition:

  • Provide a URL to documentation or source code which provides context for the suggested changes: http://ramdajs.com/docs/#pick, http://ramdajs.com/docs/#omit
  • Increase the version number in the header if appropriate.
  • If you are making substantial changes, consider adding a tslint.json containing { "extends": "dtslint/dt.json" }.

SUMMARY: We have encountered situations where we used one of the projection functions (omit, pick) and trimmed out some properties of an object only to have the compiler not catch when we later try to reference that property. This fix makes Typescript aware of what properties exist on the projections of the original Object type. I tried to break it in numerous ways and it holds up. Feedback is welcome.

@ProofOfKeags ProofOfKeags changed the title Ramda: fixed pick and omit type signatures to reflect projections [Ramda]: fixed pick and omit type signatures to reflect projections Apr 12, 2018
@typescript-bot typescript-bot added the Popular package This PR affects a popular package (as counted by NPM download counts). label Apr 12, 2018
@typescript-bot
Copy link
Contributor

typescript-bot commented Apr 12, 2018

@CaptJakk Thank you for submitting this PR!

🔔 @donnut @mdekrey @mrdziuban @sbking @afharo @teves-castro @1M0reBug @hojberg @charlespwd @samsonkeung @angeloocana @raynerd @googol @moshensky @ethanresnick @leighman - please review this PR in the next few days. Be sure to explicitly select Approve or Request Changes in the GitHub UI so I know what's going on.

If no reviewer appears after a week, a DefinitelyTyped maintainer will review the PR instead.

@typescript-bot
Copy link
Contributor

@CaptJakk The Travis CI build failed! Please review the logs for more information. Once you've pushed the fixes, the build will automatically re-run. Thanks!

@ProofOfKeags
Copy link
Contributor Author

Build error fixed by #24942

@Pajn
Copy link
Contributor

Pajn commented Apr 12, 2018

There are some problems with the Diff and Omit types. Maybe it would be better to bump the minimum TS version to 2.8 and use Exclude?

@googol
Copy link
Contributor

googol commented Apr 12, 2018

Is there a page where the problems are described? I'd be interested

@ProofOfKeags
Copy link
Contributor Author

I did not use the "standard" diff and omit types. I modified them to properly exclude things that should be excluded by omit and pick respectively. Can you clarify what you mean by "problems with the Diff and Omit" ?

@ProofOfKeags
Copy link
Contributor Author

Can I get a response on this?

@Pajn
Copy link
Contributor

Pajn commented Apr 16, 2018

I did bot mean to booxk the progress on this PR, sorry! It were just a quick thought but if you have modified and tested the types for this exact purpose I'm sure they work as expected.

omit<T>(names: ReadonlyArray<string>, obj: T): T;
omit(names: ReadonlyArray<string>): <T>(obj: T) => T;
omit<T, K extends keyof T>(names: ReadonlyArray<K>, obj: T): Omit<T, K>;
omit<K extends keyof { [index: string]: any }>(names: ReadonlyArray<K>): <T>(obj: T) => Omit<T, K>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't keyof { [index: string]: any } just string?

Copy link
Contributor Author

@ProofOfKeags ProofOfKeags Apr 16, 2018

Choose a reason for hiding this comment

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

yes. Good call.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually this won't work. When you change it to string it ruins the conditional typing that constrains the structure of the return value to which we bind the projection. The trouble is not that we want all strings, but that we want the set of indices present in the specific type the pick and omit functions are used on. If we don't do this, we can't guarantee how the projections behave when this library is used.

Unfortunately the tradeoff here is the readability of the type definitions vs the accuracy of the types that these functions produce. Since these definitions serve to aid the users I think that having a more complicated types that exclude more incorrect programs while including correct ones should be the tradeoff we make.

The desired change you requested would appear like the following:

omit(names: ReadonlyArray<string>): <T>(obj: T) => Omit<T, ???>

As you can see, we can't actually describe the set of keys that should be missing in the return type. By making it the way it is, we can preserve not just the fact that the keys being excluded are strings, but are in fact the exact strings that are reflected in the array. This only works because the strings are themselves types in 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.

Upon further inspection it appears that I misunderstood what you were asking. We can simply change the following:

K extends keyof { [index: string]: any }

to

K extends string

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah sorry for the unclear message earlier, you got exactly what I mean in the end

@ProofOfKeags
Copy link
Contributor Author

Additionally, after reviewing the documentation here: https://blogs.msdn.microsoft.com/typescript/2018/03/27/announcing-typescript-2-8/

It does not appear that the Exclude/Extract types will have the behavior desired here.

This simply means that types that are assignable to one are excluded in another. This is particularly useful for sum types but will not work for projections, which is inherently what pick and omit are. Either that, or I am misunderstanding how Exclude/Extract work but my dabbling in a quick typescript editor suggests that this won't work.

@ProofOfKeags
Copy link
Contributor Author

I have made the requested changes to reduce the verbosity of type signatures without sacrificing accuracy of the types.

@googol
Copy link
Contributor

googol commented Apr 17, 2018

Could you add the same simplification to your Omit type, changing the keyof { ... } to string?
After that and rebasing on top of master (to get the fixes from your other branch) this would be good for merge IMO.

Regarding TS2.8, Pick and Exclude can be combined to write omit: microsoft/TypeScript#21847

We did not include the Omit<T, K> type because it is trivially written as Pick<T, Exclude<keyof T, K>>.

But I'm not sure if the minimum TS version should be updated yet. We can easily change the Omit type later on anyway.

@ProofOfKeags
Copy link
Contributor Author

Just added the update to the Omit type signature and rebased with master since my other change went through. This should be good to go now.

Copy link
Contributor

@googol googol left a comment

Choose a reason for hiding this comment

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

Looks good now, thanks!

@typescript-bot
Copy link
Contributor

A definition author has approved this PR ⭐️. A maintainer will merge this PR shortly. If it shouldn't be merged yet, please leave a comment saying so and we'll wait. Thank you for your contribution to DefinitelyTyped!

@RyanCavanaugh RyanCavanaugh merged commit 5544c37 into DefinitelyTyped:master Apr 17, 2018
@ProofOfKeags ProofOfKeags deleted the feature/pick-omit-type-correctness branch April 17, 2018 15:43
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.

5 participants