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
Assignment of a partial type member to an intersection type including the partial does not compile in 2.7.0-dev.20180112 #21170
interfaceIX{x: boolean;}functionfn<T>(obj: T,props: Partial<T>): (T&IX){constxobj=objasT&IX;xobj.x=true;for(constpinprops){// The following line causes a compilation error:// TS2322: Type 'Partial<T>[keyof T]' is not assignable to type '(T & IX)[keyof T]'.xobj[p]=props[p];}returnxobj;}
Expected behavior:
This should compile since the members of Partial<T> is a subset of the members of (T & IX).
This does compile in 2.7.0-dev.20180108.
Actual behavior:
The following error is emitted when compiled:
index.ts(9,9): error TS2322: Type 'Partial<T>[keyof T]' is not assignable to type '(T & IX)[keyof T]'.
Type 'T[keyof T]' is not assignable to type '(T & IX)[keyof T]'.
Type 'T' is not assignable to type 'T & IX'.
Type 'T' is not assignable to type 'IX'.
I think this is appropriate. If IX has a property in common with T, then (IX & T)[keyof T] will result in a property that might be more-derived than in T.
It is worth nothing that this is a result of #17912. As Daniel Rosenwasser (@DanielRosenwasser) noted, the current behavior is correct. since kyeof T can overlap with keyof IX and thus the type of (T & IX)[keyof T] can be more specialized than that of T[keyof T]. in this example if T had a property x :number. the result would be number & boolean which is not just a number.
Here, you ensure that common properties of T must be compatible with those of X. The type assertion at the end is basically a way for you to say "this is not just T anymore, the properties of X have been set."
index.ts(45,9): error TS2322: Type 'Partial<T>[keyof T]' is not assignable to type 'T[keyof T]'.
Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'.
Type 'undefined' is not assignable to type 'T[keyof T]'.
To get past this problem, I cast props[p] to T[keyof T]:
This is another instance of #13195. Partial<T> adds undefined to the domain of the property types. the type system really does not distinguish between an undefined property and one that is optional (meaning either defined or not, but not defined to the value undefined). #13195 tracks that.
Activity
DanielRosenwasser commentedon Jan 12, 2018
I think this is appropriate. If
IXhas a property in common withT, then(IX & T)[keyof T]will result in a property that might be more-derived than inT.mhegazy commentedon Jan 12, 2018
It is worth nothing that this is a result of #17912. As Daniel Rosenwasser (@DanielRosenwasser) noted, the current behavior is correct. since
kyeof Tcan overlap withkeyof IXand thus the type of(T & IX)[keyof T]can be more specialized than that ofT[keyof T]. in this example ifThad a propertyx :number. the result would benumber & booleanwhich is not just a number.DanielRosenwasser commentedon Jan 13, 2018
Here's what I think would be a better workaround:
Here, you ensure that common properties of
Tmust be compatible with those ofX. The type assertion at the end is basically a way for you to say "this is not justTanymore, the properties ofXhave been set."athasach commentedon Jan 14, 2018
Ah, I overlooked the case of overlapping keys in the type intersection. Thanks for the explanation and the workaround, Daniel Rosenwasser (@DanielRosenwasser) and Mohamed Hegazy (@mhegazy).
athasach commentedon Jan 15, 2018
Daniel Rosenwasser (@DanielRosenwasser) The workaround suggested fails with
strictNullChecksand gives the following compilation error:To get past this problem, I cast
props[p]toT[keyof T]:mhegazy commentedon Jan 16, 2018
This is another instance of #13195.
Partial<T>addsundefinedto the domain of the property types. the type system really does not distinguish between anundefinedproperty and one that is optional (meaning either defined or not, but not defined to the valueundefined). #13195 tracks that.