如何检查对象中的所有字段是否都是'false'而只有一个是'true'?

How to check whether all fields in an object are 'false' while only one is 'true'?

我有一个包含许多布尔字段的对象,如下所示:

type SomeObject = {
  A: boolean
  B: boolean
  C: boolean
  ....
}

是否有easy/efficient方法来检查所有其他字段(除了指定字段)的OR是否为false

我们可以通过手动检查每个字段以暴力方式完成:

let foo:SomeObject = {
  A: false
  B: false
  C: false
}
let isA = !(foo.B || foo.C)
let isB = !(foo.A || foo.C)
let isC = !(foo.A || foo.B)

但我确信有更优雅的方法可以完成此任务。

如果您只需要编译时检查,使用映射类型和交集(为“美化”生成的类型而抛出的标识映射类型)非常容易:

type SomeObject = {
  A: boolean
  B: boolean
  C: boolean
}

type OnlyOneTrue<T extends object, K extends keyof T> = {
    [P in K] : true
} & {
    [P in Exclude<keyof T, K>]: false
};

type Identity<T> = { [P in keyof T] : T[P] }

//{ A: true; } & { B: false; C: false; }
type test = OnlyOneTrue<SomeObject, "A">;

//{ A: true; B: false; C: false; }
type pretty = Identity<test>;

如果你需要编译时类型保护以便以后可以缩小类型,那么你需要使用联合。前一个类型可以成为另一个实用类型的垫脚石:

type PossibleOnlyTrue<T extends object> = {
    [P in keyof T]: OnlyOneTrue<T, P>
}[keyof T];

//OnlyOneTrue<SomeObject, "A"> | OnlyOneTrue<SomeObject, "B"> | OnlyOneTrue<SomeObject, "C">
type union = PossibleOnlyTrue<SomeObject>;

const process = (obj: union) => {
    //type is narrowed to a union member:
    if(obj.A) {
        console.log(obj); //OnlyOneTrue<SomeObject, "A">
    }
};

如果您需要在顶部进行运行时检查,可以选择。下面是基于之前的辅助映射类型(PossibleOnlyTrueOnlyOneTrue)的类型和运行时保护:

const runtime = <K extends keyof union>(obj: union, key: K) : obj is Extract<union, { [P in K] : true }> => {
    return Object.entries(obj).every(([k,v]) => k === key || !v );
};

{
    const obj:union = { A:true, B:false,C:false };
    if(runtime(obj, "A")) obj //OK, obj is OnlyOneTrue<SomeObject, "A">
}

Playground