I have the following type declarations:
type Root = { r: string };
type A = { a: string };
type B = { b: string };
type Main = Root & (A | B);
There's the problem that the compiler can't make sure that either .a or .b are available at this point, because that's going to be validated within runtime. As soon as you create a variable of type Main, you'll specify what specialized type of Main it is. So either Root & A or Root & B.
To make sure that .a or .b are accessible within that function just do the following:
type Root = { r: string };
type AB = { a?: string, b?: string };
type Main = Root & AB;
const func = (main: Main): void => {
if ('a' in main) {
main.a!
} else {
main.b!
}
}