Reputation: 1274
When I have a type that can be something or undefined, I can easily use an if statement to check it contains something:
type MaybeString = string | undefined;
function useMaybeString(arg: MaybeString) {
if (arg !== undefined) {
printString(arg);
}
}
function printString(arg: string) {
console.log(arg)
}
But this example where my type can be one of two posibilities doesn't work:
type Foo = {foo: string};
type Bar = {bar: string};
type FooOrBar = Foo | Bar;
function useFooOrBar(arg: FooOrBar) {
if (arg.foo !== undefined) {
console.log(arg.foo);
} else {
console.log(arg.bar);
}
}
What is the solution? And why does TypeScript complain?
Upvotes: 0
Views: 770
Reputation: 7080
One of the ways is to explicitly include the other properties into both types, but set them as optional and undefined.
type Foo = {
foo: string;
bar?: undefined;
};
type Bar = {
foo?: undefined;
bar: string;
};
type FooOrBar = Foo | Bar;
function useFooOrBar(arg: FooOrBar) {
if (arg.foo !== undefined) {
console.log(arg.foo);
} else {
console.log(arg.bar);
}
}
Demo in TypeScript playground.
You can also just tell the compiler that the property is there by using Type Guards. However, you will need to check it for every condition, which can be quite cumbersome:
type Foo = {foo: string};
type Bar = {bar: string};
type FooOrBar = Foo | Bar;
function useFooOrBar(arg: FooOrBar) {
if ('foo' in arg && arg.foo !== undefined) {
console.log(arg.foo);
} else if ('bar' in arg && arg.bar !== undefined) {
console.log(arg.bar);
}
}
Demo in TypeScript playground.
Upvotes: 0
Reputation: 576
On this line
if (arg.foo !== undefined) {
it complains, because only Foo
has the foo
property, Bar
doesn't have it.
So, at this point, we can't access arg.foo
because we don't yet know if arg
is Bar
or Foo
.
I think you could use User-defined type guards:
const isFoo = (maybeFoo: FooOrBar): maybeFoo is Foo =>
(maybeFoo as Foo).foo !== undefined;
Then you can use this to assert the type:
function useFooOrBar(arg: FooOrBar) {
if (isFoo(arg)) {
console.log(arg.foo);
} else {
console.log(arg.bar);
}
}
Upvotes: 1