Repository navigation
Error on types when using multiple conditional properties #58432
Description
Activity
The fact that this works sometimes is due to #30779, which is limited no matter what. It looks like if the discriminant is optional and the property is missing, #30779 doesn't kick in, and you get the same error you'd get when trying to equate a general union-of-objects with an object-of-unions. I don't know if they'll consider this a bug or just a limitation of the sort of thing handled by #30779.
Reacted by Arkellys and Ryan Cavanaugh- changed the title
[-]Error on types when using multiple conditionnal properties[/-][+]Error on types when using multiple conditional properties[/+]on May 4, 2024 RyanCavanaugh commented
on May 6, 2024 MemberMore actionsYeah, in general a single source type
Sisn't assignable to a target typeT = T1 | T2 | T3 | Tn...just because a combinatorial explosion ofSwould ultimately result in every possible inhabitant eventually finding varying targets inT. There are exceptions, but this isn't one of them.There's almost always a better way to write the target type; I'm not really clear on the intended semantics of the type as written here so can't advise much
- addedDesign LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed
on May 6, 2024 If it helps to give a more concrete example, I need this for a React component with several props required or unnecessary depending on other props. For example:
<Chip removable={isRemovable} // Optional onRemove={noop} // Required if `removable` is `true`, unnecessary if removable is `false` label="test" // Required when no `children`, unnecessary when `children` is defined > Test {/* Required when `label` is not defined */} </Chip>
/** * @typedef {object} ChildlessProps * @property {string} label */ /** * @typedef {object} ParentProps * @property {any} children */ /** * @typedef {object} RemovableProps * @property {true} removable * @property {Function} onRemove */ /** * @typedef {object} StaticProps * @property {false} [removable=false] */ /** * @typedef {object} BaseProps * Other properties.... */ /** * @typedef {BaseProps & (RemovableProps | StaticProps) & (ParentProps | ChildlessProps)} ChipProps */
I was handling these conditions with
propTypes, but since prop types check will be removed on React 19 I decided to try and strengthen my JSDoc so that it could handle them instead (I don't use TS).I'm not sure there is another way to write this?
typescript-bot commented
on May 10, 2024 ContributorMore actionsThis issue has been marked as "Design Limitation" and has seen no recent activity. It has been automatically closed for house-keeping purposes.
🔎 Search Terms
"jsdoc conditional properties", "typescript conditonnal properties", "type conditon"
🕗 Version & Regression Information
This is the behavior in every version I tried, and I reviewed the FAQ for entries about conditional types
⏯ Playground Link
https://www.typescriptlang.org/play/?ts=5.4.5#code/FASwdgLgpgTgZgQwMZQAQGED2YAmIIjboBqCANgGLkDOaA3sKk6kgPwBcqiZtwAvsFCRYiFBmx4CRUmQAqMAK71GzJJwiKo-QeGjxkaLLnyEwAIRlUey5qgBGHLjS0Che0YYknsF8vKWoDLZ26prabiIGqGYItIEqTAic1BrgAOb8ANyCSNgpqND5ALyoABS5YHAgaZwxcQBkZUaSpr5ymqgAPuLGUuaWzgCUqI2lzd5gJH4d3eN9U5RDw0UAfE7WwBX5MFAQCjDmmJhkqCWlAG7knHZHZFAIYMPXt-dgp2uol2TZwIUQpXRUElUAAiBAggA09k4Oz2BzMt1KGiUwz4gyAA
💻 Code
🙁 Actual behavior
When using a second set of conditional properties, the first one throws a type error while it passes when using the condition alone.
If I remove the second condition, or that I passes
trueorfalsedirectly, I get not error:Somehow, when passing the
cproperty – which is not supposed to be required – it passes:It also passes if I only declare the
arequired property:So
bandcare indeed optional.🙂 Expected behavior
I expect the type checking to be the same whether I passes one or multiple conditional properties. I believe all of these should work:
Additional information about the issue
For the context, I'm trying to make some properties required based on other property values.
I realize that maybe there is better way to do this in TS, but actually my problem is in JSDoc, and I believe I'm more limited on what I can do with JSDoc synthax.
My real code is on a React component, and unlike the example above, even passing all the optional properties throws the error.