The below is an example of the types which I have
type Place = {
address: string
}
type Location = {
latLng: string
}
type User = {
name: string
} & (Place | Location)
So when I try to use it while parsing the data
const { name, address, latLng } = user;
It shows a TS error Property 'address' does not exist on type 'User'
Technically I know that either address or latLng will be present but not both, which is how I need and my logic will validate it when parsing the data. But how to let TS know that about it and remove this error?
This is a great place to use never
. This lets you set up two "configurations" of the User, which will have either a Place or a Loc. The Place type enforces an undefined latLng, while the Loc type enforces an undefined address. A User is one of ({name: string} & Place) | ({name: string} & Loc)
, so while all three fields exist in both types in the union, address or latLng will be undefined based on the presence of the other.
type Place = {
address: string;
latLng?: never;
};
type Loc = {
latLng: string;
address?: never;
};
type User = {
name: string;
} & (Place | Loc);
function test1() {
// Valid, latLng is undefined
const user: User = { name: "User", address: "1234 Somewhere St" };
const { address, latLng, name } = user;
}
function test2() {
// Valid, address is undefined
const user: User = { name: "User", latLng: "123,456" };
const { address, latLng, name } = user;
}
function test3() {
// Invalid, both address and latLng are present
const user: User = {
name: "User",
latLng: "123,456",
address: "1234 Somewhere St",
};
const { address, latLng, name } = user;
}
This gives you a type which can have either a defined address
or latLng
but not both. You can destructure both values out of the user
, but one or the other will be undefined.