I want the option
to have a path
attribute or a children
attribute, but not both. And can be correctly derived during use。
First, I do this:
type Option = {name: string, path: string} | {name: string, children: Option[]}
declare const option: Option
option.path // Property 'path' does not exist on type 'Test'
Then, I use this way: Does Typescript support mutually exclusive types?
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = (T | U) extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;
type Option = {name: string} & XOR<{path: string}, {children: Option[]}>
// const option: Option = {name: '1', path: ''} // ok
// const option: Option = {name: '1', children: []} // ok
// const option: Option = {name: '1', value: '', children: []} // error, but ok
declare const option: Option
if (option.children) option.children.concat()
else option.path.toLocaleUpperCase()
if (option.path) option.path.toLocaleUpperCase()
else option.children.concat() // why ?!
So, I want to know what is the reason for the above two errors? And how to fix them?