You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Union of partial types: common super type of all union members is not assignable to union type #33243
Search Terms: union partial type assignable structure
Code
// Data typesinterfaceKey{type: "key";key: string;}interfaceKeyValue{type: "key-value";key: string;value: string;}typeEither=Key|KeyValue;typeCommon=Pick<Either,"type"|"key">;// Test cases// Structurally-compatible assignmentconsteither: PartialEither=nullasanyasCommon;// Type-guardingif(either.type==="key-value"){either.value;}// Problematic type definitions// Using this intermediate type so I can still rely on 'type' as the discriminant property of// the PartialEither type. The naive// Pick<Either, "type" | "key"> & Partial<Omit<Either, "type" | "key">>// would lose the relationship between `type` and shape, causing the type guard above to fail.type_PartialEither<TextendsEither>=Pick<T,"type"|"key">&Partial<Omit<T,"type"|"key">>;typePartialKey=_PartialEither<Key>;typePartialKeyValue=_PartialEither<KeyValue>;typePartialEither=PartialKey|PartialKeyValue;// This type seems to force the compiler to reinterpret the partial types into a slightly// different representation that's logically equivalent but properly assignable. From:// https://stackoverflow.com/questions/57780109/union-of-partial-types-in-typescript-cant-be-type-narrowedtypeExpand<T>=Textends infer O ? {[KinkeyofO]: O[K]} : never;// Change the definition to this version to see the test cases above work.// type PartialEither = Expand<PartialKey | PartialKeyValue>;
Expected behavior: Line 21, the structurally-compatible assignment, compiles, without a workaround. Using the Expand type has no effect on assignability.
Actual behavior: Line 21 does not compile, stating
Type 'Pick<Either, "key" | "type">' is not assignable to type 'PartialEither'.
Type 'Pick<Either, "key" | "type">' is not assignable to type '_PartialEither<KeyValue>'.
Type 'Pick<Either, "key" | "type">' is not assignable to type 'Pick<KeyValue, "key" | "type">'.
Types of property 'type' are incompatible.
Type '"key" | "key-value"' is not assignable to type '"key-value"'.
Type '"key"' is not assignable to type '"key-value"'.
Using the Expand helper type workaround fixes the assignability problem.
changed the title [-]Union of partial types is not assignable to common sub-type of all union members[/-][+]Union of partial types: common super type of all union members is not assignable to union type[/+]on Sep 4, 2019
The reason why Expand works is probably because of this #30779; both approaches do not work pre 3.5. It seems that PartialEither as defined is not considered a discriminated union in that logic. TypeScript clearly understands that PartialEither is a discriminated union though, evidenced by:
Activity
[-]Union of partial types is not assignable to common sub-type of all union members[/-][+]Union of partial types: common super type of all union members is not assignable to union type[/+]jack-williams commentedon Sep 4, 2019
My answer was a mess!
The reason why
Expandworks is probably because of this #30779; both approaches do not work pre 3.5. It seems thatPartialEitheras defined is not considered a discriminated union in that logic. TypeScript clearly understands thatPartialEitheris a discriminated union though, evidenced by:Smaller repro: