为什么不能使用函数断言打字稿中的var不为空
我正在玩打字稿,我注意到了一些意想不到的事情。我可以在showCarInfo2函数中看到一个错误
为什么我不能将函数用于非空断言?
在第一个函数showCarInfo1中car.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 链接到代码