首页 > 解决方案 > 为什么在 strictNullChecks 开启时 null 变量仍会扩大以键入任何内容?

问题描述

TypeScript DocsstrictNullChecks说如果是真的,它不应该再扩大类型。并且 typeofnul应该是null.

let nul = null; // typeof nul = any
let undef = undefined; // typeof undef = any

操场

strictNullChecks在 TSConfig 选项卡中打开Playground。nul和的类型undef仍然是any。为什么?</p>

更新:

谢谢@jcalz。我发现了一些有趣的东西:

// strictNullChecks=true;
let z = null; // hover on z, quick info shows: let z: any <--
type A = typeof z; // type A = null

操场

// strictNullChecks=false;
let z = null; // hover on z, quick info shows: let z: any 
type A = typeof z; // type A = any <---

Playground(关闭 strictNullCheck)

标签: typescript

解决方案


当 TypeScript 2.0 发布时,您链接的文档可能是准确的。但是当 TypeScript 2.1 发布时,它引入了改进的any推理,在microsoft/TypeScript#11263中实现。

从那时起,如果您启用--noImplicitAny,当您将非const变量初始化为nullor undefined(或根本不初始化它)时,编译器将其类型推断为any而不是nullor undefined,即使--strictNullChecks启用,甚至对于 TypeScript 代码(如反对检查 JavaScript 代码):

let nLet = null; // any
let uLet = undefined; // any

var nVar = null; // any
var uVar = undefined; // any

const nConst = null; // null
const uConst = undefined; // undefined

动机似乎是,当您使用nullor初始化变量时undefined,您很可能稍后将其更改为其他内容,并且该any类型允许控制流分析进行后续缩小:

let x = undefined;
while (!x) {
  if (Math.random() < 0.5) x = "finished";
}
x // string
x.toUpperCase(); // okay
x.toFixed(); // error

在这里,编译器允许分配 a stringto x(如果x是 type则禁止),并且一旦你退出循环,它undefined也会看到它x是 type的,所以它让你把它当作 a而不是其他任何东西(例如一)。stringstringnumber


即使在初始分配时,控制流分析也会将这些变量的表观类型缩小到null并且undefined如果您只是将变量注释为 type 则不会发生这种情况any

let nLet = null; // any
nLet.x // error, Object is possibly 'null'

let uLet = undefined; // any
uLet.x // error, Object is possibly 'undefined'

let aLet: any;
aLet.x // no error

null因此,在实践中,您可能不会观察到变量初始化为or的太多问题undefined

Playground 代码链接


推荐阅读