lei li
lei li

Reputation: 1342

A type accept none or one of two properties but reject both

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

Answers (2)

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

devdgehog
devdgehog

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 {}.

Playground

Upvotes: 4

Related Questions