-
Notifications
You must be signed in to change notification settings - Fork 13k
Description
π Search Terms
"generic conditional" "omit conditional" "keyof conditional"
π Version & Regression Information
- Occurs in all versions available in TS Playground
β― Playground Link
π» 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 Omit
ted 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.