How do we represent a function or a React component that requires one of two properties, but not both, to exist in TypeScript?
We can create a base interface and extend that with two more interfaces that include and exclude those specific properties. Let's assume that we expect to have either displayName
or firstName
for a user.
interface BaseUser {
id: string;
age: number;
// ... other base user properties
}
interface UserWithDisplayName extends BaseUser {
displayName: string;
firstName?: never;
}
interface UserWithFirstName extends BaseUser {
displayName?: never;
firstName: string;
}
type User = UserWithFirstName | UserWithDisplayName;
We use the "never" keyword to indicate that one property should not be set at the same time as the other. The or ("|") operator is used to create a union where a User
can only have one of the exclusive properties.
Now we can use the User
type in a function as follows.
const normalizeUser = ({
age,
displayName,
firstName,
id,
}: User) => { /* ... */}
Or if we're creating a React component:
const UserDetails: React.FunctionComponent<User> = ({
age,
displayName,
firstName,
id,
}: User) => { /* ... */ };