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
Empty Object type hides other types when mixing them with statements or expressions #49952
This is the behaviour in every version I tried. The documentation does not say what should happen when {} is combined with other types during control flow inference.
// bad: {}[], should be: ({} | "bob")[]constarray=[bob,empty]// bad: {}, should be: {} | "bob"typeA=typeofarray[number]// bad: never, should be: "bob"typeXA=Extract<typeofarray[number],string>// bad: {}[], should be: (Date | {})[]// Bad, because you can still recover Date: (a0[index] instanceof Date) implies that it really is a Dateconsta0=[newDate(),empty]// ok: ({} | Date)[]typeA0=(Date|{})[]// bad: {}[], should be: ({} | 42)[], or ({} | number)[]consta1=[42,empty]// ok: ({} | 42)[]typeA1=({}|42)[]// ok: {}[]// Ok, because ("typescript" in a2[index]) does not imply that (a2[index].typescript === "rocks")consta2=[{typescript: "rocks"},empty]// ok: ({} | { typescript: "rocks" })[]typeA2=({typescript: "rocks"}|{})[]
Using if:
functionifAction(names: boolean){if(names){returnbob}else{return{}asconst}}// bad: {}, should be: {} | "bob"typeI=ReturnType<typeofifAction>// bad: never, should be: "bob"typeXI=Extract<ReturnType<typeofifAction>,string>
Using switch-case + call to function (same result when directly return the constants)
Right, as everything except null and undefined is an object in javascript, this actually makes sense.
What doesn't make so much sense, is that typescript does not always do the reduction, e.g. when explicitly taking the union of both types like in the TBO type above.
As a second thought, the same reasoning should apply { toString(): string }, which it does most of the time. Inconsistencies only get worse/change when adding generics into the mix (see type-hints / .d.ts outputs): Playground Link
Subtype reduction happens "sometimes" where "sometimes" is largely determined by performance constraints. It's never wrong to subtype-reduce so any observed behavior is from an equally-valid set of behaviors.
It's never wrong to subtype-reduce so any observed behavior is from an equally-valid set of behaviors.
I agree. I tried expressions [a, b] and observed the inferred types:
Only those expressions where the type of one variable is a proper subtype of the other have been reduced to a single type. After looking at those cases, this really prevents errors.
For other cases, the item type of the array was the union of both types.
When there is a discriminant property, you should be fine.
When both types only overlap without a discriminant property. By definition, it is only safe to use common properties. There will be dragons when you use conditional types or control flow analysis on properties defined only in one of the types. It would definitely help, if the effective type would be more general -> only allow to observe properties common to both types (like with member access).
Activity
MartinJohns commentedon Jul 19, 2022
This is the expected subtype reduction behavior. Note that
{}does not mean "empty object type". It means any type exceptnullandundefined.pyBlob commentedon Jul 20, 2022
Right, as everything except
nullandundefinedis an object in javascript, this actually makes sense.What doesn't make so much sense, is that typescript does not always do the reduction, e.g. when explicitly taking the union of both types like in the
TBOtype above.As a second thought, the same reasoning should apply
{ toString(): string }, which it does most of the time. Inconsistencies only get worse/change when adding generics into the mix (see type-hints / .d.ts outputs):Playground Link
RyanCavanaugh commentedon Jul 20, 2022
Subtype reduction happens "sometimes" where "sometimes" is largely determined by performance constraints. It's never wrong to subtype-reduce so any observed behavior is from an equally-valid set of behaviors.
pyBlob commentedon Jul 20, 2022
I agree. I tried expressions
[a, b]and observed the inferred types:github-actions commentedon Jun 8, 2023
This issue has been marked as 'Not a Defect' and has seen no recent activity. It has been automatically closed for house-keeping purposes.