首页 > 解决方案 > TypeScript:对象在联合类型上可能为空

问题描述

我有一个基本接口,其中至少需要两个属性之一。

interface Base {
    someProp: { subProp: string; } | null;
    condProp1?: boolean;
    condProp2?: boolean;
}

interface WithProp1 extends Base {
    condProp1: true;
}

interface WithProp2 extends Base {
    condProp2: true;
}

export type MyType = WithProp1 | WithProp2;

MyType当我在检查someProp不为空检查condProp1或检查真实性之后尝试使用时condProp2,编译器仍然认为someProp可能是null.

function doSomething(myType: MyType) {
    if (myType.someProp && (
        myType.condProp1 && myType.someProp.subProp === 'foo' ||
        myType.condProp2 && myType.someProp.subProp === 'bar')) {
        console.log("It's true, isn't it?  It's really true.");
    }
}

doSomething(),myType.someProp.subProp给出一个编译时错误,说someProp可能是null. 如果我在函数签名中替换MyType为,则不会发生这种情况。Base

// Compiles fine
function doSomethingBase(myType: Base) {
    if (myType.someProp && (
        myType.condProp1 && myType.someProp.subProp === 'foo' ||
        myType.condProp2 && myType.someProp.subProp === 'bar')) {
        console.log("It's true, isn't it?  It's really true.");
    }
}

将顺序切换myType.someProp.subProp === 'foo' && myType.condProp1为第一行的解决方法,但不是第二行。知道为什么会发生这种情况或如何解决它(我可以使用 a!但我不应该这样做)?似乎是编译器中的一个错误。

我正在使用 TSC 版本 3.5.3。 TypeScript 游乐场

标签: typescript

解决方案


我怀疑这实际上是一个编译器错误;我不太了解内部结构,但我怀疑编译器将初始保护子句评估为 type Base,然后将内部子句评估为WithPropX, 并且正在丢失 myType asWithPropX已经被防范 null someProp的信息.

您可以通过反转检查的顺序来解决此问题,因此更具体的类型推断发生在条件的早期(然后 someProp 空检查发生在编译器知道 myType 是 aWithPropX而不是 a 的点Base):

function doSomething(myType: MyType) {
    if (myType.condProp1 && myType.someProp && myType.someProp.subProp === 'foo' ||
        myType.condProp2 && myType.someProp && myType.someProp.subProp === 'bar') {
        console.log("It's true, isn't it?  It's really true.");
    }
}

这个问题似乎与您在此处观察到的有关。


推荐阅读