Without using extension
Using XOR described here: https://stackoverflow.com/a/53229567/8954109
// Create a type that requires properties `a` and `z`, and one of `b` or `c`
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = (T | U) extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;
interface Az {
a: number;
z: number;
}
interface B {
b: number;
}
interface C {
c: number;
}
type XorBC = XOR<B, C>;
type AndAzXorBC = Az & XorBC;
type MyData = AndAzXorBC;
const ok1: MyData = { a: 0, z: 1, b: 2 };
const ok2: MyData = { a: 0, z: 1, c: 2 };
const badBothBC: MyData = {
a: 0, z: 1,
b: 2,
c: 3
};
const badNoBC: MyData = { a: 0, z: 1 };
const badNoZ: MyData = { a: 0, b: 2 };
Produces these errors for invalid types:
src/App.tsx:30:7 - error TS2322: Type '{ a: number; z: number; b: number; c: number; }' is not assignable to type 'AndAzXorBC'.
Type '{ a: number; z: number; b: number; c: number; }' is not assignable to type 'Az & Without<C, B> & B'.
Type '{ a: number; z: number; b: number; c: number; }' is not assignable to type 'Without<C, B>'.
Types of property 'c' are incompatible.
Type 'number' is not assignable to type 'undefined'.
30 const badBothBC: MyData = {
src/App.tsx:35:7 - error TS2322: Type '{ a: number; z: number; }' is not assignable to type 'AndAzXorBC'.
Type '{ a: number; z: number; }' is not assignable to type 'Az & Without<C, B> & B'.
Property 'b' is missing in type '{ a: number; z: number; }' but required in type 'B'.
35 const badNoBC: MyData = { a: 0, z: 1 };
~~~~~~~
src/App.tsx:17:3
17 b: number;
~
'b' is declared here.
src/App.tsx:36:7 - error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'AndAzXorBC'.
Type '{ a: number; b: number; }' is not assignable to type 'Az & Without<C, B> & B'.
Property 'z' is missing in type '{ a: number; b: number; }' but required in type 'Az'.
36 const badNoZ: MyData = { a: 0, b: 2 };
~~~~~~
src/App.tsx:13:3
13 z: number;
~
'z' is declared here.