Reputation: 1342
I want a type, that accept none or one of two properties but reject both of them. How to build that?
interface I{
...
}
let a:I={} //accept empty
let b:I={f1:true} // accept only f1
let c:I={f2:true} // accept only f2
let d:I={f1:true,f2:true}//reject both of f1 and f2
Upvotes: 2
Views: 136
Reputation: 1337
Or you could use more generic solution:
type Source = {
p1: boolean;
p2: number;
p3: string;
}
type OneOfOrEmpty<T extends {
[key: string]: any;
}, P extends keyof T = keyof T> = {
[K in P]?: never;
} | (P extends keyof T ? Pick<T, P> & {
[K in keyof Omit<T, P>]?: never
} : never)
let test: OneOfOrEmpty<Source> | undefined;
test = {}; // works
test = { p1: true }; // works
test = { p2: 5 }; // works
test = { p3: "" }; // works
test = { p1: false, p3: "" }; // gives an error
Upvotes: 1
Reputation: 625
You can use an union of types having properties of never types.
type F1 = {
f1: boolean; f2?: never;
}
type F2 = {
f1?: never; f2: boolean;
}
type NotF = {
f1?: never; f2?: never;
}
type I = F1 | F2 | NotF;
let a: I = {} //accept empty
let b: I = { f1: true } // accept only f1
let c: I = { f2: true } // accept only f2
let d: I = { f1: true, f2: true } //reject both of f1 and f2
NotF is declared to allow {}.
Upvotes: 4