【问题标题】:How to pull null check into function in typescript如何将空检查拉入打字稿中的函数
【发布时间】:2022-01-18 17:13:04
【问题描述】:

我有一些代码,其中有几个函数需要对对象进行空值检查,然后对其进行处理,或者如果它为空值则抛出错误,如下所示:

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();
}

但是,当我这样做时,打字稿不再知道检查后,object 肯定存在。有没有干净的方法来做到这一点?

This question 看起来很相似,但实际上并不能让我节省太多代码重复,因为我仍然需要设置 if

【问题讨论】:

  • 这很令人困惑,我不完全确定你在问什么,doThingOne/doThingTwo 什么时候将对象扩展为方法?为什么要使用单独的功能?目标是什么?你能做一个最小的、可重复的例子吗? stackoverflow.com/help/minimal-reproducible-example
  • 我只是想减少重复。 object,如果存在的话,它是一个有一些方法的类型。不管我是想打电话给object.doThingOne() 还是使用object.someProperty,问题都是一样的。
  • 这是一个代码示例,在首选方法上有错误:typescriptlang.org/play?#code/…
  • 没有办法让像requireObject() 这样的函数调用影响任意范围内值的状态。您可以使用assertion function 来获得类似的结果,但您需要将受保护的东西作为参数传递,例如requireObject(object)。见here。如果这种方法满足您的需求,我可以写一个答案,否则答案基本上是“不,你不能这样做”,我想我可以写成答案,也许吧。告诉我。
  • @jcalz 断言函数似乎正是我正在寻找的!

标签: typescript types null


【解决方案1】:

您可以使用! 运算符告诉编译器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类型,所以代码有点混乱。它应该可以工作(我实际上还没有尝试过),但您可能需要考虑将变量命名为其他名称。

【讨论】:

    【解决方案2】:

    没有办法编写requireObject() 并影响object 的类型,因为编译器看不到requireObject()object 有任何关系。 (如果编译器可以管理由于函数内部封闭变量的突变而导致的所有可能的状态变化,那将是很好的,但它在计算上不可行。有关一般问题,请参阅microsoft/TypeScript#9998。)

    您可以将object 传递给requireObject() 并注释requireObject()assertion function。断言函数必须实现为void-returning(因此它们不会返回任何内容),并且带注释的返回类型是asserts x is Y 形式的“断言谓词”(其中x 是其中一个的名称函数参数)或者只是asserts x,如果你想说xtruthy

    这给了我们:

    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
    }
    

    Playground link to code

    【讨论】:

      猜你喜欢
      • 2018-05-22
      • 1970-01-01
      • 2019-07-30
      • 2020-03-26
      • 2021-11-19
      • 2021-05-30
      • 2022-12-05
      • 2022-07-20
      • 2020-04-24
      相关资源
      最近更新 更多