Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'Omit' should alias a distinct mapped type (for display purposes) #31104

Open
DanielRosenwasser opened this issue Apr 24, 2019 · 8 comments · Fixed by #31115
Open

'Omit' should alias a distinct mapped type (for display purposes) #31104

DanielRosenwasser opened this issue Apr 24, 2019 · 8 comments · Fixed by #31115
Assignees
Labels
Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Experience Enhancement Noncontroversial enhancements Fix Available A PR has been opened for this issue Help Wanted You can do this Suggestion An idea for TypeScript

Comments

@DanielRosenwasser
Copy link
Member

Today, Omit will expand to Pick<Exclude<...>, ...> in quick info, error messages, etc. which is gross.

By defining Omit as its own conditional type, we can get a slightly nicer display, though it will introduce duplication of code between the two helpers.

@DanielRosenwasser DanielRosenwasser added the Experience Enhancement Noncontroversial enhancements label Apr 24, 2019
@weswigham
Copy link
Member

By defining Omit as its own conditional type, we can get a slightly nicer display, though it will introduce duplication of code between the two helpers.

Actually it's the mapped type - you'd want to inline the Pick, not the Exclude. So:

type Omit<T, U> = {[K in Exclude<keyof T, U>]: T[K]};

❤️

@RyanCavanaugh RyanCavanaugh added the Suggestion An idea for TypeScript label Apr 25, 2019
@DanielRosenwasser DanielRosenwasser self-assigned this Apr 25, 2019
@DanielRosenwasser
Copy link
Member Author

Yeah, I figured it out as I made the change.

@DanielRosenwasser DanielRosenwasser changed the title 'Omit' should alias its own conditional for display 'Omit' should alias a distinct mapped type (for display purposes) Apr 25, 2019
@DanielRosenwasser
Copy link
Member Author

Looks like this is getting reverted because of #31190.

@jcalz
Copy link
Contributor

jcalz commented May 3, 2019

Maaaaybe something like this?

// default type parameter trickery
type Omit<T, K extends keyof any, X extends keyof T = Exclude<keyof T, K>> = {
  [P in X]: T[X]
};

interface Test {
  required: string;
  optional?: string;
  readonly viewonly: string;
}

declare const x: Omit<Test, "required" | "optional" | "notPresent" >;
x.viewonly = "okay"; // error!
// Cannot assign to 'viewonly' because it is a read-only property.

// typeof x is Omit<Test, "required" | "optional" | "notPresent", "viewonly">>

Pro: The type parameter X maintains the homomorphicitinessitude that you need in the mapped type.
Pro: The name Omit will appear instead of Pick and Exclude in IntelliSense

Con: Default type parameters are not meant for this, who knows what could happen
Con: IntelliSense will show the value of X which could be confusing.


Or what about

// conditional type inference antics
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>> extends infer U
  ? { [P in keyof U]: U[P] }
  : never;

interface Test {
    required: string;
    optional?: string;
    readonly viewonly: string;
}

declare const x: Omit<Test, "required" | "optional" | "notPresent">;
x.viewonly = "okay"; // error!
// Cannot assign to 'viewonly' because it is a read-only property.

// typeof x is { readonly viewonly: string; }

Pro: Still homomomomomorphic
Pro: The name Omit appears instead of Pick, and in the concrete cases the actual distinct mapped type shows up.

Con: Conditional type inference isn't exactly meant for this either, who knows what can happen

@DanielRosenwasser DanielRosenwasser added Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Help Wanted You can do this labels Sep 21, 2020
@DanielRosenwasser
Copy link
Member Author

The following type

type Omit<T, ExcludedKeys extends keyof any> = {
    [K in keyof T as Exclude<K, ExcludedKeys>]: T[K]
};

now maintains modifiers thanks to @ahejlsberg's pull request at #40633.

@DanielRosenwasser
Copy link
Member Author

I think this change will be contingent on performance tests though.

@DanielRosenwasser
Copy link
Member Author

Also, @weswigham may want to weigh in since he has a PR out at #37608, but I think it would be undesirable to add a 3rd type parameter just to use a default type argument.

@ExE-Boss
Copy link
Contributor

For TS 4.0 and older, you can use @Jack-Works’s type-challenges/type-challenges#141.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Experience Enhancement Noncontroversial enhancements Fix Available A PR has been opened for this issue Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
6 participants