TypeScript:联合类型上的对象可能为null

时间:2019-09-05 19:11:49

标签: typescript

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

MyType

当我在检查someProp不为空后尝试使用condProp1 并且在检查condProp2someProp的真实性之后时,编译器仍然认为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

将顺序切换为!可作为第一行而不是第二行的解决方法。知道为什么会发生这种情况或如何解决(我可以使用{{1}},但不必这样做)吗?好像是编译器中的错误。

我正在使用TSC版本3.5.3。 TypeScript playground

2 个答案:

答案 0 :(得分:1)

我怀疑这实际上是一个编译器错误;我不太了解内部结构,但是我怀疑编译器正在将初始保护子句评估为Base类型,然后将内部子句评估为WithPropX,并且丢失了有关作为WithPropX的myType已经被防止使用null someProp。

您可以通过反转检查的顺序来解决此问题,因此更具体的类型推断会在条件中更早地发生(然后,在编译器知道myType是{{1 }},而不是WithPropX

Base

This issue似乎与您在这里观察到的情况有关。

答案 1 :(得分:0)

我喜欢@Chris Helad说:

  

我怀疑编译器正在将初始的保护子句评估为Base类型,然后将内部子句评估为WithPropX,并且丢失了信息,即myType as WithPropX已经被保护为null someProp。

因此,编译器可能会这样工作:

function doSomething(myType: MyType) {
  if (myType.someProp && ( // myType is type of WithProp1 | WithProp2 AND someProp is defined
    myType.condProp1 && myType.someProp.subProp === 'foo' || // condProp1 is defined, so, myType is typeof WithProp1 (forgot that someProp is defined)
    myType.condProp2 && myType.someProp.subProp === 'bar')) { // condProp2 is defined, so, myType is typeof WithProp2 (forgot that someProp is defined)
    console.log(`It's true, isn't it?  It's really true.`);
  }
}

要击败它,您可以定义一个简单的type guard来告诉编译器实际类型:

function hasProp(t: MyType): t is MyType & {someProp: NonNullable<MyType['someProp']>} {
  return !!t.someProp;
}

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