我有一些代码,其中有几个函数需要对对象进行null检查,然后对其进行处理,或者在对象为null时抛出错误,如下所示:
interface SomeObject {
doThingOne: () => string;
doThingTwo: () => string;
}
let object: SomeObject | null;
function doThingOne() {
if(!object) {
throw new Error('Object is null!');
}
// Typescript knows that object is not null, so it's fine with accessing its properties/methods
return object.doThingOne();
}
function doThingTwo() {
if(!object) {
throw new Error('Object is null!');
}
return object.doThingTwo();
}
我想把空校验拉到一个函数中,以减少重复的代码,比如:
interface SomeObject {
doThingOne: () => string;
doThingTwo: () => string;
}
let object: SomeObject | null;
function requireObject() {
if(!object) {
throw new Error('Object is null!');
}
}
function doThingOne() {
requireObject();
// Typescript no longer knows that object is defined, so it gets mad at the next line
return object.doThingOne();
}
function doThingTwo() {
requireObject();
return object.doThingTwo();
}
然而,当我这样做时,typescript不再知道在检查之后,object
肯定存在。有干净的方法吗?
这个问题看起来很相似,但实际上不会让我节省太多代码重复,因为我仍然需要设置if
由于编译器不认为requireObject()
与object
有任何关系,因此无法编写requireObject()
并影响object
的类型。(如果编译器能够管理由于函数内部封闭变量的突变而导致的所有可能的状态变化,那就太好了,但这在计算上是不可行的。有关一般问题,请参阅microsoft/TypeScript#9998。(
您可以做的是将object
传递到requireObject()
中,并注释requireObject()
是一个断言函数。断言函数必须实现为void
-返回(这样它们就不会返回任何内容(,并且带注释的返回类型是一个";断言谓词";形式为asserts x is Y
(其中x
是函数参数之一的名称(,或者如果您想说x
是真的,则仅为asserts x
。
这就给了我们:
function requireObject(x: any): asserts x {
if (!x) {
throw new Error('something is falsy here');
}
}
现在我们可以做到这一点而不会出错:
let object: SomeObject | null;
function doThingOne() {
requireObject(object);
return object.doThingOne(); // okay
}
function doThingTwo() {
requireObject(object);
return object.doThingTwo(); // okay
}
游乐场链接到代码
您可以使用!
运算符告诉编译器object
肯定会包含一个值。
return object!.doThingOne();
我尽量避免做那种事。以后很容易遇到麻烦。相反,我会将requireObject
函数定义为始终返回一个对象。
function requireObject(): object {
if (!object) {
throw new Error('Object is null!');
}
return object;
}
然后你可以这样称呼它:
object = requireObject();
由于requireObject
总是返回object
类型,编译器将知道此时object
不是null
。
现在唯一的问题是,因为object
实际上是TypeScript类型,所以代码有点混乱。它应该可以工作(我实际上还没有尝试过(,但您可能需要考虑用其他方式命名变量。