为什么不能使用函数断言打字稿中的var不为空

我正在玩打字稿,我注意到了一些意想不到的事情。我可以在showCarInfo2函数中看到一个错误

为什么我不能将函数用于非空断言?

在第一个函数showCarInfo1car.passengers !== null,一切正常。

interface Car {
  name: string;
  passengers: string[] | null;
}

const car: Car = {
  name: 'Seat',
  passengers: ['Andrew', 'Kate'],
}

function showCarInfo1(car: Car) {
  if(car.passengers !== null) {
    console.log(`${car.name}${car.passengers.map(passenger => ` ,${passenger}` )}`)
  } else {
    console.log(car.name)
  }
}

showCarInfo1(car)

const hasPassengers = (car: Car) => car.passengers !== null;

function showCarInfo2(car: Car) {
  if(hasPassengers(car)) {
    console.log(`${car.name}${car.passengers.map(passenger => ` ,${passenger}` )}`)
  } else {
    console.log(car.name)
  }
}

回答

编译器不会跨函数边界执行控制流分析。虽然编译器可以这样做会很好,但它会非常昂贵。一般来说,编译器必须模拟所有可能的程序运行方式,然后才能对类型做出结论,并且假设您希望程序在宇宙热死之前编译,就会有限制。有关此问题的详细讨论,请参阅microsoft/TypeScript#9998,“控制流分析中的权衡”。

在没有这种情况自动发生的情况下,您可以使用一种技术来告诉编译器意图hasPassengers充当其参数的类型保护。您可以将其注释为用户定义的类型保护函数。返回类型是表单的类型谓词arg is Type它是以下的特殊子类型boolean(因此用户定义的类型保护仅适用于 return 的函数boolean):

interface NonNullCar extends Car {
  passengers: string[];
}

const hasPassengers = (car: Car): car is NonNullCar => car.passengers !== null;

如果您进行上述更改,您的代码将根据需要编译:

function showCarInfo2(car: Car) {
  if (hasPassengers(car)) {
    console.log(`${car.name}${car.passengers.map(passenger => ` ,${passenger}`)}`) // no error
  } else {
    console.log(car.name)
  }
}

Playground 链接到代码


以上是为什么不能使用函数断言打字稿中的var不为空的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>