Skip to content

TS not properly resolving keys of generic conditional type when used in OmitΒ #57417

@BlueLdr

Description

@BlueLdr

πŸ”Ž Search Terms

"generic conditional" "omit conditional" "keyof conditional"

πŸ•— Version & Regression Information

  • Occurs in all versions available in TS Playground

⏯ Playground Link

https://www.typescriptlang.org/play?pretty=true&ts=5.3.3#code/C4TwDgpgBAQghgZwgHgGIBs4HMoQB7AQB2AJglAEYD2V6EcRAfFALxQDeAUFFAGY0B+AFxQEwAE4BLIlgDcnAL5QAZFAAU3KBmy4CxMlAkBXaAI6aevTFhHGI8njwpxxIsVJkBtALoOoSkS5HPmthPjh0JD8nFzcJaTlNBU4ASk5OUEgoAHlgAAsIcXgkVnNLQRFqWnoiPwQqAFsIfISwqgoAKwgAY2B5ZIzwaABZEAAFcSowBDRrXUJSciq6BmY2YpRtLGZVbIbJYGRcgqLECAAaKABrCBAqXlgz2exGRnTuqiIxXTgGsDpSs8cPgFgZljVGGorNgRFsUqxmEFDENHkgANK3chsG53B4bIGMPwAeiJhjyknIhUm4igFN0kF6EBIlwYJFp5AA7lRxFcElAwJNIOJ0CBNB8vsBKGcMSARBsZVioAAiepNFoyJWyKAkqAAUQASvrsvqRAByFWNZrkjWm9lQIhUSWIBCSLBEOAUAHAKjIrIAAyV-CoSqgAB8oAA6KN+zSZaDHQryzGlHH3HL5RNnPzi76Ok5J2Xp-PS5NsC1q61YTWxlGjBUp25p0YTKYzLaEzQ6lqU8TUu0AOWyABV6T1CCQxZ9vg0QDKRHXS8rVVaEprtaSDUaTVBzcv1VXbXSHU6EC63R6vT641AA0GQ+GoxGw3q8N10EYSChAzQlZdv8Hn0fZhw11V930-ZByxXDU-zvQCo0YGMFCAA

πŸ’» Code

type Base<Flag extends boolean> = {
  foo?: string;
} & (
  Flag extends true ? {
    flag: true;
    bar: string[];
  } : {
    flag?: false;
    bar: string;
  }
)

type OtherBase = {
  foo?: boolean;
  something?: object;
}

type MyProps<Flag extends boolean> = Base<Flag> & Omit<OtherBase, keyof Base<Flag>>

const example = <Flag extends boolean>(flag: Flag) => {
  type BaseKeys = keyof Base<Flag>;
  // this error is expected, and is working properly
  const baseKey: BaseKeys = "something"; // ERROR: '"something"' is not assignable to type `"foo" | ...`
  type OtherBaseKeys = keyof OtherBase;
  const otherBaseKey: OtherBaseKeys = "something";
  type MyKeys = keyof MyProps<Flag>;
  // this error is NOT expected
  const myKey: MyKeys = "something"; // ERROR: '"something"' is not assignable to type `"foo" | ... | Exclude<"foo", "foo" | ...> | Exclude<"something", "foo" | ...>`
}

πŸ™ Actual behavior

"something" is not assignable to keyof MyProps<Flag>. It is Omitted from OtherBase even though it is never a possible key of Base, no matter what the value of the generic is or how the condition resolves.

Interestingly, "something" still appears as an autocomplete suggestion when typing a value for myKey.

πŸ™‚ Expected behavior

The resolved type of keyof MyProps<Flag> should (effectively) be "something", and thus "something" should be assignable to myKey.

Additional information about the issue

I'm trying to combine two types that have some overlap by omitting the common keys in one of them and then intersecting them. But this seems to be omitting all keys from the one type, when the other type is a generic conditional type. In the example, TS knows that "something" is not in BaseKeys, and is in OtherBaseKeys, but Omit<OtherBaseKeys, BaseKeys> is somehow omitting "something". The conditional type clearly has a known set of keys that stays the same no matter how the condition resolves. So why doesn't TS resolve the keys properly when using Omit?

I know this can be done (and works properly) with a discriminated union instead of a conditional. It originally was a DU, but I had to change it to a conditional to get some other usages working properly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions