-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Conditional spread results in weird union type, with duplicates #41386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Any clue if this is working as intended @ahejlsberg @weswigham @amcasey? |
Another example that @sandersn had come up with interface Animal {
name: string;
owner?: string;
}
function billOwner(pet: Animal) {
return {
...(pet.owner && pet),
paid: false
}
} |
I'm a bit surprised the same type is in there twice, but otherwise it's an effect of us not performing union subtype reduction in object literal spreads. |
Right - I actually thought that that was where the slowdown originally came from: creating every combination of types of spreads, followed by subtype reduction on extremely similar types. I guess it was just creating each possibility, which I think is still exponential. |
The multiple-of-the-same-object-type thing is something that's always been an unfortunate possibility in a spread. That example you have there gives the same output in older TS, too. |
const clone = clonePet(pet, true)
clone.location = undefined //probably not desired? I just read the 4.1 RC release notes. Didn't realize the optional props are now expected behaviour. |
The duplicate is just "unfortunate" but it's a distraction. I think this behavior is inconsistent otherwise because the real thing I'm reporting is that we're not getting optional properties, and I can't coherently explain this behavior. |
The duplicate is directly the cause of the behavior (which also exists in older TS versions provided you use single-property additions). This is because our spread object-combining logic only permits combining exactly two types, so if you have three types (even if two are identical), we skip the whole simplification process (which is the only thing that produces optional properties) and do the big union-all-the-possibilities plan. |
Expected:
clonePet
returns type{ name: string, kind: string, age?: number, location?: string, owner?: object }
Actual:
clonePet
returns the following type:The text was updated successfully, but these errors were encountered: