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
Partially discriminated union with explicitly defined key loosens inferred typeΒ #55239
exporttypeDomNodeStyle=ElementStyle|ImageStyle;exporttypeElementStyle={tagName: string;style: {key: string;value: string}[];children: (ElementStyle|ContentStyle)[];};exporttypeContentStyle={content: string};exporttypeImageStyle={tagName: 'img';imageSource: string|null;style: {key: string;value: string}[];children: (ElementStyle|ContentStyle)[];};constimage={tagName: 'img',imageSource: 'https://example.com/image.jpg',// This is correct. Compiler requires `imageSource` because tagName is `img`.style: [],children: []};functiondoSomeWork(node: DomNodeStyle){if(image.tagName==="img"){// Narrowing is not occurring correctlyconsole.log(image.imageSource)// Error message: Property 'imageSource' does not exist on type 'ElementStyle'}}
π Actual behavior
For a partially discriminated union, when trying to access a narrowed field value, the compiler does not properly narrow the type. This forces the user to use the in operator to determine if the field exists. When instantiating the object though, the compiler does correctly infer that the field from the narrowed type needs to exist.
π Expected behavior
I would expect the compiler to properly narrow the type if the explicitly defined union is set. In this case, if tagName is img, the compiler should infer that imageSource is required and available. If tagName is any other string value, the compiler should fall back to ElementStyle for the type.
This is not a bug; the underlying problem here is that image.tagName === "img" isn't actually sufficient to narrow the union to ImageStyle: image might still be an ElementStyle whose tagName just happens to be "img". You'd need a way to say string & not "img" for this to work correctly. See #4196 and #29317.
I guess I had assumed that the compiler would automatically pick the narrower type but being explicit with a negative type is probably the better approach.
I'll close this as a dupe since it is the intended functionality.
Activity
fatcerberus commentedon Aug 2, 2023
Pretty sure this is a duplicate of a few issues.
This is not a bug; the underlying problem here is that
image.tagName === "img"isn't actually sufficient to narrow the union toImageStyle:imagemight still be anElementStylewhosetagNamejust happens to be"img". You'd need a way to saystring & not "img"for this to work correctly. See #4196 and #29317.You can actually see this in action by commenting out
imageSourcein the object literal - there is no compiler error andimageis inferred to be a validElementStyle.cwoolum commentedon Aug 2, 2023
I guess I had assumed that the compiler would automatically pick the narrower type but being explicit with a negative type is probably the better approach.
I'll close this as a dupe since it is the intended functionality.
everett1992 commentedon Aug 2, 2023
Woah, that's the first time I've seen the
^?comment on the playground, that's really useful!MartinJohns commentedon Aug 2, 2023
But that wouldn't be safe. Your type
ElementStyleexplicitly says that anystringis a validtagName, that includes"img".Link to the TypeScript type narrowing issue.