使用 Typescript 中的映射类型强制布尔值 属性 为真或假

Force a boolean property to be true or false using mapped types in Typescript

我有一个接口(以下称为 Foo),它包含一个布尔值 属性(以下称为 booleanProp)。鉴于此,我想将其包装在映射类型中,以便能够将变量的类型限制为 Foo 对象 属性 booleanProp 设置为 true,或者false

示例如下:

interface Foo {
    readonly booleanProp: boolean;
}

type BooleanPropIsTrue<T extends { readonly booleanProp: boolean }> = {
    readonly [ P in keyof T]: T[P];
} & {
    readonly booleanProp: true;
};

const falseFoo: Foo = {
    booleanProp: false
};

const trueFoo: Foo = {
    booleanProp: true
};

if (falseFoo.booleanProp === true) {
    // ERROR: type 'boolean' is not assignable to type 'true'.
    const foo: BooleanPropIsTrue<Foo> = falseFoo;
}

if (trueFoo.booleanProp === true) {
    // ERROR: type 'boolean' is not assignable to type 'true'.
    const foo: BooleanPropIsTrue<Foo> = trueFoo;
}

if (trueFoo.booleanProp === true) {
    // Works
    const foo: BooleanPropIsTrue<Foo> = {
        ...trueFoo,
        booleanProp: true
    };
}

我希望所有 3 个 if 子句都能工作。有什么建议吗?

(注意:我知道避免使用映射类型的替代选项,无需指出)

这种基于检查缩小类型的行为所涉及的特征是discriminated union。在没有联合的情况下,Typescript 不会跟踪此类检查(因为就编译器而言,没有潜在的类型缩小)。简单的解决方法是将 Foo 转换为可区分的联合:

type Foo = {
    booleanProp: true;
} | {
    booleanProp: false;
}

type BooleanPropIsTrue<T extends { readonly booleanProp: boolean }> = {
    readonly [ P in keyof T]: T[P];
} & {
    readonly booleanProp: true;
};

// We introduce some randomness, if we assign { booleanProp: false } we can't  even do the check as the compiler will know booleanProp is always false 
const falseFoo: Foo = Math.random()> 0.5 ? {
    booleanProp: false
} : {
    booleanProp: true
};

const trueFoo: Foo = {
    booleanProp: true
};

if (falseFoo.booleanProp === true) {
    //Works 
    const foo: BooleanPropIsTrue<Foo> = falseFoo;
}

if (trueFoo.booleanProp === true) {
    //Works 
    const foo: BooleanPropIsTrue<Foo> = trueFoo;
}

if (trueFoo.booleanProp === true) {
    // Works
    const foo: BooleanPropIsTrue<Foo> = {
        ...trueFoo,
        booleanProp: true
    };
}