“ not null”类型防护在else分支中解析为“从不”

时间:2019-07-09 09:49:24

标签: typescript types type-conversion

我创建了一个类型防护,用于检查参数是否恰好是null

function isNotNull<T> (arg: T): arg is Exclude<T, null> {
  return arg !== null
}

当我对其进行测试时,then分支正常工作:它从类型中剥离了null

const value: string | null = 0 as any
if (isNotNull(value)) {
  // value is of type `string` here
}

但是,它在never分支中变成了else

const value: string | null = 0 as any
if (isNotNull(value)) {
  // `value` is of type `string` here
} else {
  // `value` is of type `never` here
}

我希望它在null分支中解析为else

我该如何实现?

1 个答案:

答案 0 :(得分:2)

这里的问题是作业:

const value: string | null = 0 as any

编译器知道value是一个常量,因此它永远不能为null。

使用let并不会变得更好:

let value: string | null = 'foo';
if (isNotNull(value)) {
  // `value` is of type `string` here
} else {
  // `value` is of type `never` here
}

再次,打字稿编译器知道该值不为空。

但是,如果分配一些Typescript无法推断恒定值的内容,那么您将在string分支中拥有期望的if,在null中拥有else:< / p>

function isNotNull<T> (arg: T): arg is Exclude<T, null> {
  return arg !== null
}

let value: string | null = foo();

if (isNotNull(value)) {
  // `value` is of type `string` here
} else {
  // `value` is of type `null` here
}

function foo(): string | null {
    return "foo"
}

此外,即使最后一个示例也仅在您将strictNullChecks编译器选项设置为true时才有效。如果您尚未启用strictNullChecks,则无法从null中排除type,并且if分支将是string,与string | null相同因此,never只剩下else

编辑: 当strictNullChecks关闭时,此操作不起作用的原因非常有趣。在那种情况下,类型string | nullstring是相同的。这意味着value实际上具有类型string,而Exclude<string, null>只是string(因此仍然包括null),因此else子句是左侧,类型为never的类型为value