Skip to content

fix(lib/es5): Preserve Omit in output - #35889

Closed
ExE Boss (ExE-Boss) wants to merge 2 commits into
microsoft:masterfrom
ExE-Boss:lib/es5/preserve-omit
Closed

ExE Boss (ExE-Boss) wants to merge 2 commits into
microsoft:masterfrom
ExE-Boss:lib/es5/preserve-omit

Conversation

@ExE-Boss

@ExE-Boss ExE Boss (ExE-Boss) commented Dec 28, 2019 •

Copy link
Copy Markdown
Contributor

I’ve been using this without problems in my local version of the TypeScript library.


Fixes #34793

@dragomirtitian

Copy link
Copy Markdown
Contributor

I am pretty sure this option was considered when Omit was added. It was rejected because it does not preserve optionality and readonly-ness. Pick is homomorphic since it maps over K where K extends keyof T and thus preserves modifiers.

Since your type maps over Exclude<keyof T, K> it is not homomorphic. Only types that map over keyof T where T is a type parameter or that map over K where K is type parameter with K extends keyof T are homomorphic.

type Omit2<T, K extends keyof any> = {
    [P in Exclude<keyof T, K>]: T[P];
};

type U = {
    a: number,
    readonly b?: number
} 

type R = Omit2<U, 'a'> // has b: number | undefined;
type R2 = Omit<U, 'a'> // has  readonly b?: number | undefined;

Playground Link

@ExE-Boss

Copy link
Copy Markdown
Contributor Author

That is probably also why auto‑fix is broken with this.

@ypresto

Yuya Tanaka (ypresto) commented Jan 8, 2020 •

Copy link
Copy Markdown
Contributor

FYI:

The documentation for "homomorphic" and Pick is here: https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types


#35889 (comment)
type R = Omit2<U, 'a'> // has b: number | undefined; is actually // has b: number; (optional is NOT copied too).


I tried

type Omit2<T, K extends keyof any> = K extends keyof T ? {
  [P in Exclude<keyof T, K>]: T[P];
} : Omit<T, K>;

but does not solve the problem 😂

@ypresto

Yuya Tanaka (ypresto) commented Jan 8, 2020 •

Copy link
Copy Markdown
Contributor

Then my question is: why Omit uses K extends keyof any instead of K extends keyof T? (I sometimes specify wrong or unnecessary K for Omit)

@ExE-Boss

ExE Boss (ExE-Boss) commented Jan 8, 2020 •

Copy link
Copy Markdown
Contributor Author

The reason is probably because this is the more correct Object.assign(…) type:

declare function __assign<T, S>(target: T, source: S): Omit<T, keyof S> & S;

To be 100% correct, the result should include properties from T that are optional in S.

@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compiled .d.ts output for Omit is verbose and semantically inconsistent

4 participants