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
This is the behavior in every version I tried, and I reviewed the FAQ for entries about Interfaces & generics (though this doesnt really fit into any of the FAQs)
interfaceSourceData{id: string;// some other datastart_date: string;end_date?: string;}interfaceUseableData{id: string;// some other datastart_date: Date;end_date?: Date;}functiontransform(props: SourceData): UseableData{return{// Error `end_date` is of type `string | Date | undefined`
...props,start_date: newDate(props.start_date),
...(props.end_date&&{end_date: newDate(props.end_date)})};}
🙁 Actual behavior
I am getting an error on the return statement saying that it is not assignable to type 'UseableData' where end_date is of type string | Date | undefined.
Why I believe this is a bug is because I am adding the Date version of end_date if the optional end_date string exists in the first place. So if end_date doesnt exist, then it would return the undefined type from ...props, and if the end_date string did exist, it would get parsed through the Date class and be added to the return object. So the only possible return type for end_date is Date | undefined which matches that in UseableData
🙂 Expected behavior
No type error should occur because we are optionally adding the end_date key to the return object only if it has a value
🥸 Partial workaround
I'm aware that I can use the ternary operator like so:
Which is fine if you are just grabbing values from the returned object. However if you were to call Object.keys() on the returned object with end_date being specifically defined as undefined by the ternary operator, then end_date would appear in its result.
Where as going:
Seems like a #30581-type issue, quite similar to #45769. TS doesn't do "distributive control flow analysis"; it doesn't analyze your object literal imagining that props.end_date is a string and then imagining that it is undefined; instead it analyzes the literal once, and if props.end_date is string | undefined when considering ...props, then that won't be affected by the later check implied by props.end_date && { end_date: new Date(props.end_date) }. The control flow analysis there doesn't expand in scope to the whole object literal. It wouldn't be scalable to do it that way.
It's actually even worse than that; there's also #42384: checking props.end_date doesn't narrow props because props isn't of a discriminated union type (or of a union type at all). So even if TS did analyze the whole object literal multiple times, it would fail to do what you want:
if(typeofprops.end_date==="undefined"){// remember, empty strings are falsyprops.end_date// undefined 👍constoops={ ...props}oops.end_date// string | undefined, NOT NARROWED 👎}
So I don't imagine this will be easily fixable or changed.
If I were to try to do what you're doing, the workaround I'd use is to explicitly destructure into separate variables and then reassemble them like
Thank you very much for your insight @jcalz! I can see why implementing something like this would be problematic at best.
I was not aware that you could create a encompassing ...rest variable that just contained everything not specifically defined in the deconstruction. So thank you for that as well!
since that's much easier on the poor, overburdened type checker.
It is certainly doing a lot haha.
Ill close this as the workaround you provided works well.
Thanks!
Bug Report
🔎 Search Terms
Spread, Object, Type, Optional, Interface
🕗 Version & Regression Information
⏯ Playground Link
Playground link
💻 Code
🙁 Actual behavior
I am getting an error on the return statement saying that it is not assignable to type 'UseableData' where
end_date
is of typestring | Date | undefined
.Why I believe this is a bug is because I am adding the
Date
version ofend_date
if the optionalend_date
string exists in the first place. So ifend_date
doesnt exist, then it would return theundefined
type from...props
, and if theend_date
string did exist, it would get parsed through theDate
class and be added to the return object. So the only possible return type forend_date
isDate | undefined
which matches that inUseableData
🙂 Expected behavior
No type error should occur because we are optionally adding the
end_date
key to the return object only if it has a value🥸 Partial workaround
I'm aware that I can use the ternary operator like so:
Which is fine if you are just grabbing values from the returned object. However if you were to call
Object.keys()
on the returned object withend_date
being specifically defined asundefined
by the ternary operator, thenend_date
would appear in its result.Where as going:
Wont include
end_date
in the returned object.Hence why this is only a partial workaround
The text was updated successfully, but these errors were encountered: