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
Accessing property in union of object types fails for properties not defined on all union members #12815
typeA={a: string;}typeB={b: string;}typeAorB=A|B;declareconstAorB: AorB;if(AorB.a){// use AorB.a}
Expected behavior:
The code compiles without errors. Even though a doesn't (necessarily) exist on all the constituents of the union, the fact that it exists on some should allow me to check for .a and use it if it is present.
Actual behavior:
Typescript complains: "Property a does not exist on type AorB... Property a does not exist on type B."
Reacted by swen-ihealthlabs, Arthur Silva, Simon Márton, Jared, zachlite, Elie Steinbock, Kevin LeStarge, Rajdeep Barman, Noriyuki Motoyoshi, Craig M. and 18 more
Reacted by Piotr Dąbrowski, Mor Shemesh, Ilias Gazdaliev, Ivan Soroka, Yihao Gao, Linkjun, Jon Catmull, Matt Curtis, TraJoeWu, RafiHenig and 17 more
Reacted by Linkjun, Ctibor Laky, Ninni Victoria Bergquist, NexusDeveloper and Krisztina Závecz
Reacted by Sameera Kumarasingha, Joel Kuntz, Victor Pietro Moreno and Clark
The issue here is that because B doesn't declare an a property, it might at run-time have an a property of any possible type (because you can assign an object with any set of properties to a B as long as it has a b property of type string). You can make it work explicitly declaring an a: undefined property in B (thus ensuring that B won't have some random a property):
Reacted by Matt Mueller, Santiago Carmuega, rafaelcichocki, Josh Kelley, Connie Leung, Rustam Agzamov, Elie Steinbock, Karol Majewski, Rajdeep Barman, Mike Marcacci and 35 more
Reacted by vileen, Andrew Steinheiser, Batjaa Batbold, Ricardo Villanueva, mookil, Steven Prins, Matej Murín, Carter Wooten, Linkjun, Oskar Duwe and 28 more
Reacted by Linkjun, Drazen Bjelovuk, Vint Prox, Alexey Petrochenkov, raghavcinch, csdal and duke79
Reacted by Denis Zhbankov, M.K. Safi, Daniel Guerra, David Furlong, Karson Kalt, Karén Zh, Athina Bekakou and Alan Riaño
If you define a: undefined on type B, you'll have to set it to undefined when you create/pass a variable.
To get around that, you can declare a as a?: undefined, and typescript will be happy if you omit it.
Reacted by Nicholas Papadopoulos, rafaelcichocki, Dylan Markow, Noriyuki Motoyoshi, Apples, Eirini Pappa, Will Bamford, Mick Dekkers, P.J. Swesey, Joshua Rabiu and 11 more
If I understand the comments correctly, this should work (but throws; tested on playground): Is this a bug or not? 🤔
typeLinkProps={to: string;onClick?: undefined;// Link specific props:target: string;}typeButtonProps={to?: undefined;onClick: Function;// Button specific props:disabled: boolean;}typeActionProps=LinkProps|ButtonProps;constAction=(props: ActionProps)=>props.to ?
'Link with target: '+props.target// Error not on ButtonProps
:
'Button with disabled: '+props.disabled;// Error: not on LinkPropsAction({to: 'dssd',target: '_blank'});
Reacted by ilpoo, Jonathan Gold, Erik Berdonces Bonelo, Kasparas Anusauskas, Nikolai Hegelstad, Victor Glindås, Sviataslau Salamennik, Alex Lerdkanlayanawat , Tomas Trepka, Seth Killian and 15 more
If you define a: undefined on type B, you'll have to set it to undefined when you create/pass a variable.
To get around that, you can declare a as a?: undefined, and typescript will be happy if you omit it.
might be better a?: never, now you can not assign undefined by mistake
Reacted by sai-github, mookil, lagebaue, David Simmer, Paul Berg, Andy Edwards, R.G. and José Rodrigues
What if you don't give a name to each of the members of the union? (can't make a type assertion as above without a name for the asserted type, can I?)
typeu="str"|{prop:"val"};functionf(arg:u){returnarg.prop}// TypeScript: Property 'prop' does not exist on type 'u'
Reacted by Anupam, williamfligor, Carsten Englert, Volodymyr Ozhekhovskyi, Colin McParland, Marco Biedermann, mookil, JoeLangewayClear, Iván Pedro Benavides Matillas, Victorry and 6 more
interface A { x: number;}
interface B { y: string;}
function doStuff ( q: A | B ) {
if ( 'x' in q) {
// if type A...
}
else {
// if type B...
}
}
Excerpt From: Basarat Ali Syed. “TypeScript Deep Dive.” Apple Books.
a property on an object and can be used as a type guard, and the TypeScript can know which type you used.
Reacted by Raoul Rodriguez, Sebastián Talero, catalin, Daniel Gill, Adam Price, Dylan Markow, Drazen Bjelovuk, Stevo, Nicolas Vitaterna, Gaurav Gupta and 81 more
Reacted by andreykostenko, Lautaro De Filippo, Arthur Woimbée and Telokis
Reacted by Artur Klesun, Jon Catmull, Sebastiaan Hols, Anny Chagas, Shane Cavaliere, edk55, roman-gula, Gökhan, Ctibor Laky, Ismail and 11 more
Reacted by Artur Klesun, Anny Chagas, Shane Cavaliere, Gökhan, Ian Leue, Ctibor Laky, Ismail, pierre, proambb, adam tombleson and 6 more
Reacted by Ctibor Laky, Dan Seethaler, Ismail, proambb, François Billioud, Alfred Doh-Nani and Daniil
The issue here is that because B doesn't declare an a property, it might at run-time have an a property of any possible type (because you can assign an object with any set of properties to a B as long as it has a b property of type string). You can make it work explicitly declaring an a: undefined property in B (thus ensuring that B won't have some random a property):
you might be thinking you're testing for the non-zeroness of foo in one branch of the union, but hitting a plain object through an aliased value in another branch. There's no ambiguity what you're trying to do with "foo" in a.
Ryan Cavanaugh (@RyanCavanaugh) Thanks for the answer, but I'm having trouble understanding it. Could you put it another way please?
upd: Turns out there is an open issue for this: #1260. But I still don't understand your point about ambiguity. if ("foo" in a) is clearly as unsound as if (a.foo).
Reacted by Joshua Turner, Robert Clover, Godfrey Hobbs and Marlon U. Marcello
Activity
akarzazi commentedon Dec 10, 2016
The doc says :
To get the same code working, we’ll need to use a type assertion:
http://www.typescriptlang.org/docs/handbook/advanced-types.html
Then in your sample:
ahejlsberg commentedon Dec 10, 2016
The issue here is that because
Bdoesn't declare anaproperty, it might at run-time have anaproperty of any possible type (because you can assign an object with any set of properties to aBas long as it has abproperty of type string). You can make it work explicitly declaring ana: undefinedproperty inB(thus ensuring thatBwon't have some randomaproperty):ethanresnick commentedon Dec 12, 2016
Makes perfect sense. Brain fart.
ocombe commentedon Mar 14, 2018
If you define
a: undefinedon type B, you'll have to set it toundefinedwhen you create/pass a variable.To get around that, you can declare
aasa?: undefined, and typescript will be happy if you omit it.donaldpipowitch commentedon May 30, 2018
If I understand the comments correctly, this should work (but throws; tested on playground): Is this a bug or not? 🤔
paddotk commentedon Jul 30, 2018
I don't understand this at all. Isn't
if ((<A>AorB).a)the same as using if(A.a)because you're forcing it back to typeA?artola commentedon Jun 29, 2019
might be better
a?: never, now you can not assignundefinedby mistakeescKeyStroke commentedon Aug 30, 2019
What if you don't give a name to each of the members of the union? (can't make a type assertion as above without a name for the asserted type, can I?)
mookilyu commentedon Dec 24, 2019
Any solution?
xxzhong21330 commentedon Dec 26, 2019
i find a solution on book :
Excerpt From: Basarat Ali Syed. “TypeScript Deep Dive.” Apple Books.
a property on an object and can be used as a type guard, and the TypeScript can know which type you used.
cartok commentedon Oct 7, 2020
Does not work for me 07.10.2020
And I think that this behavior of TS is not good because it does not help a developer much...
thorn0 commentedon Jan 14, 2021
Bdoesn't declare anaproperty, it might at run-time have anaproperty of any possible type" (Accessing property in union of object types fails for properties not defined on all union members #12815 (comment))'a' in AorBis supported as a type guard (Accessing property in union of object types fails for properties not defined on all union members #12815 (comment))RyanCavanaugh commentedon Jan 14, 2021
Georgii Dolzhykov (@thorn0) yes, because if you write code like
you might be thinking you're testing for the non-zeroness of
fooin one branch of the union, but hitting a plain object through an aliased value in another branch. There's no ambiguity what you're trying to do with"foo" in a.thorn0 commentedon Jan 14, 2021
Ryan Cavanaugh (@RyanCavanaugh) Thanks for the answer, but I'm having trouble understanding it. Could you put it another way please?
upd: Turns out there is an open issue for this: #1260. But I still don't understand your point about ambiguity.
if ("foo" in a)is clearly as unsound asif (a.foo).