If you’re truly after “one property or the other” and not both you can use never
in the extending type:
interface MessageBasics {
timestamp?: number;
/* more general properties here */
}
interface MessageWithText extends MessageBasics {
text: string;
attachment?: never;
}
interface MessageWithAttachment extends MessageBasics {
text?: never;
attachment: string;
}
type Message = MessageWithText | MessageWithAttachment;
// 👍 OK
let foo: Message = {attachment: 'a'}
// 👍 OK
let bar: Message = {text: 'b'}
// ❌ ERROR: Type '{ attachment: string; text: string; }' is not assignable to type 'Message'.
let baz: Message = {attachment: 'a', text: 'b'}
Example in Playground