【问题标题】:how can a function check for null in typescript?函数如何在打字稿中检查 null?
【发布时间】:2018-05-22 18:11:43
【问题描述】:

在 typescript 2.6 中,我想编写一个执行 null 检查的函数。当我启用严格的空检查时,typescript 2.6 抱怨以下代码。 (注意直接使用空检查时有效)

已编辑:更正 notNullOrUndefined,因为它没有检查 foo

interface A {
  foo: string | undefined;
}
const notNullOrUndefined = (a: A): boolean => {
  return a.foo != null;
}
const len = (a: A): number => {
  //if (a.foo != null) {
  if (notNullOrUndefined(a)){
    return a.foo.length;
  }
  return 0;
} 

这里是一个例子:example

解决这个问题的打字稿方法是什么?

【问题讨论】:

  • 似乎您应该检查aa.foo 是否为空或未定义。类似const len = (a: A): number => a && a.foo && a.foo.length || 0;
  • 如果你使用 (a && a.foo != null) 会怎样

标签: javascript typescript


【解决方案1】:

编辑:更新以反映修复有问题的错字:这个问题有点令人困惑,因为你的 notNullOrUndefined() 根本不检查 a.foo,所以它们会有所不同也就不足为奇了。

请注意,启用--strictNullChecks 时,您已定义len(),因此a 参数是A,因此不能为空或未定义。所以你不必在len() 函数实现中检查a 本身;相反,您需要确保传递给len() 的任何内容都是有效的A。所以notNullOrUndefined() 是一个坏名字,因为您检查的是参数的foo 值,而不是参数本身。随意将其更改为fooPropertyIsNotNull();我暂时先离开它。

这里的主要问题是 TypeScript 识别出 if (a.foo != null) { ... }type guard,并在 { ... } 子句中将 a.foo 缩小为 string。但是类型保护不会自动将propagate 排除在功能之外,因此TypeScript 不理解notNullOrUndefined() 本身充当类型保护。

幸运的是,这个问题很常见,TypeScript 提供了user-defined type guards:如果你有一个返回 boolean 的函数,它缩小了其中一个参数的类型,你可以将 boolean 返回类型更改为 类型谓词,使用x is T 语法。这是notNullOrUndefined()

const notNullOrUndefined = (a: A): a is { foo: string } => {
  return a.foo != null;
}

所以函数签名说:如果你传入一个A,它将返回一个布尔值。如果它返回true,则传入的参数将缩小为{ foo: string }。现在你不会得到任何错误,如你所愿:

interface A {
  foo: string | undefined;
}
const notNullOrUndefined = (a: A): a is { foo: string } => {
  return a.foo != null; // checking a.foo
}
const len = (a: A): number => {
  if (notNullOrUndefined(a)){
    return a.foo.length; // okay
  }
  return 0;
} 

希望对你有帮助,祝你好运!

【讨论】:

  • 谢谢...你完全回答了我的问题。我玩得太多了,所以我粘贴了一个损坏的例子......也更正了。虽然您的解决方案解决了我的问题,但您有什么建议可以在您检查的对象嵌套时如何扩展?
  • 显而易见的答案是只检查嵌套属性而不是整个对象(isDefined(a.foo.bar) 而不是isFooBarDefined(a))。否则,您可能需要两个接口,一个具有所有属性非空,另一个具有所有属性可为空,如this answer。没有类型保护传播或条件映射类型,现在没有伟大的解决方案。
【解决方案2】:

您需要同时检查aa.foo。例如,即使未启用严格的 null 检查,此代码也可以工作:

const len = (a: A): number => {
  if (a != null && a.foo != null){
    return a.foo.length;
  }
  return 0;
} 

如果您确实启用了严格的 null 检查,则您已经知道 a 不是未定义的,然后您可以使用您的注释行:

const len = (a: A): number => {
  if (a.foo != null){
    return a.foo.length;
  }
  return 0;
} 

如果您想在单独的函数中执行测试,那么您应该将该函数设为类型断言。例如,您可以从foo 类型中删除undefined,但在您不知道foo 是否存在的任何地方使用Partial<A>

interface A {
  foo: string;
}
const notNullOrUndefined = (a: Partial<A>): a is A => {
  return a != null && a.foo != null;
}
const len = (a: Partial<A>): number => {
  if (notNullOrUndefined(a)){
    return a.foo.length;
  }
  return 0;
} 

【讨论】:

    【解决方案3】:

    这就是我现在讨厌strictNullChecks 的原因。它不支持从函数内部进行类型检查以“冒泡”到调用检查的位置。

    if (a && a.foo) {
       return a.foo.length;
    }
    

    按预期工作。对我来说,将以下内容包装在一个函数中......

    const hasFoo(a: A) => !!a && 'foo' in a && typeof a.foo === 'string';
    
    ...
    
    if (hasFoo(a)) {
       return a.foo.length;
    }
    
    ...
    

    ...应该作为初始检查。然而,事实并非如此。

    一个解决方案(也是唯一一个)是使用新的!. 后缀表达式。这声称该值确实被声明为预期的类型。

    if (hasFoo(a))
    {
       return a.foo!.length;
    }
    

    【讨论】:

    【解决方案4】:

    此代码将检查是否为空。

    "use strict";
    
    function isNull(something: any) {
        return something === null;
    }
    
    function checkForNull() {
        console.log(isNull(''));
        console.log(isNull(null));
        console.log(isNull(undefined));
    }
    
    checkForNull();
    

    输出:

    false
    true
    false
    

    【讨论】:

    • 我知道这会检查 null...问题是我如何调用一个检查 null 作为先决条件的函数,然后访问可能为 null 的字段,这样 typescript 2.6 就不会抱怨
    • 我想我只是没有得到这个问题。我将至少暂时编辑我的答案,看看你是否能告诉我我遗漏了你的问题的哪一部分。
    • OP 询问的是 TypeScript 的编译时错误,而不是生成的 JavaScript 的运行时行为。
    • 我还是不明白。对不起。这段代码完全没有编译错误。我读了你的答案@jcalz,我只能看到你不能在运行时将某些东西设置为空,所以不能编写试图这样做的代码。我很高兴删除我发布的大量无用代码,但我仍然希望了解问题的真正含义。如果您定义了一个类型,则以后不能将其分配给 null。还有别的吗?
    猜你喜欢
    • 1970-01-01
    • 2019-07-30
    • 2022-01-18
    • 2021-05-30
    • 2022-07-20
    • 2020-03-26
    • 2021-11-19
    • 1970-01-01
    • 2014-06-19
    相关资源
    最近更新 更多