Typescript Neither, Either, but Not Both Properties

Cri*_*ole 7 typescript

I'd like to assert that a type can have neither, either, but not both of a pair of properties.

The following does not work, although I'd have assumed it would. Apparently having a: never and b: never means that I have to provide both?

I also tried using {} in place of NeitherANorB which compiled and ran, but did not catch the fourth case where I incorrectly passed both options.

interface JustA {
    a: string;
    b: never;
}

interface JustB {
    a: never;
    b: string;
}

interface NeitherANorB {
    a: never;
    b: never;
}

type NotBothAAndB = JustA | JustB | NeitherANorB;

function testMe(x: NotBothAAndB) {
    console.log(x);
}

testMe({}); // OK
testMe({ a: "HI!" }); // OK
testMe({ b: "SUP?" }); // OK
testMe({ a: "HI!", b: "SUP?" }); // NOT OK
Run Code Online (Sandbox Code Playgroud)

kay*_*ya3 13

您可以使用{property?: never}{property?: undefined}表示某个属性不应存在。请注意,即使在前一种情况下,只要属性具有 value ,就允许存在undefined,因为这正是 Typescript 处理可选属性的方式。所以这应该做你想要的:

type NotBoth =
    | {a: string, b?: never}
    | {a?: never, b: string}
    | {a?: never, b?: never}

// ok
const test1: NotBoth = {a: 'foo'};
const test2: NotBoth = {b: 'bar'};
const test3: NotBoth = {};
// error: 'string' is not assignable to 'undefined'
const testFail: NotBoth = {a: 'foo', b: 'bar'};
Run Code Online (Sandbox Code Playgroud)

游乐场链接

为了方便起见,这里有一个用于构造这样的联合的辅助类型,其中最多允许使用某些属性之一:

// Simplify<T> just makes the resulting types more readable
type Simplify<T> = T extends infer S ? {[K in keyof S]: S[K]} : never
type NoneOf<T> = Simplify<{[K in keyof T]?: never}>
type AtMostOneOf<T> =
    | NoneOf<T>
    | {[K in keyof T]: Simplify<Pick<T, K> & NoneOf<Omit<T, K>>>}[keyof T]

type NotBoth = AtMostOneOf<{a: string, b: string}>
Run Code Online (Sandbox Code Playgroud)

游乐场链接