Reputation: 46432
I wonder if there's a sane way how to get the following to work.
interface IPerson {
firstName: string
lastName: string
}
interface IPet {
name: string
}
type IPersonOrPet = IPerson | IPet
function fullname(p: IPersonOrPet) {
if (p.name) { // **1**
return p.name // **2**
} else {
return p.firstName + ' ' + p.lastName // **3**
}
}
I see that with discriminated unions, sich things are simple, but I can't see why nothing works for non-discriminated unions:
p.name
exists. But isn't there a better way than using any
?{name: ''}
). As I don't know how to solve the two previous points, I could only guess here.Upvotes: 1
Views: 515
Reputation: 3506
You can use the in
operator as a type guard which typescript will use to properly narrow the types within the condition bodies.
function fullname(p: IPersonOrPet) {
if ('name' in p) { // **1**
return p.name // **2**
} else {
return p.firstName + ' ' + p.lastName // **3**
}
}
Upvotes: 4
Reputation:
The proper way to address this in TypeScript is to use a type guard, a function whose return type confirms or rejects your hypothesis that p
belongs to Person
or to Pet
.
Check out the return type of the isPerson()
function:
interface Person {
firstName: string
lastName: string
}
interface Pet {
name: string
}
type PersonOrPet = Person | Pet
function fullname(p: PersonOrPet) {
if (isPerson(p)) {
return p.firstName + ' ' + p.lastName;
} else {
return p.name;
}
}
function isPerson(p: PersonOrPet): p is Person {
return 'firstName' in p && 'lastName' in p;
}
Upvotes: 2