如何抑制TypeScript"错误TS2533:对象可能是'null'或'undefined'"?

gra*_*nal 166 typescript

我有一个类型:

type tSelectProtected = {
  handleSelector?: string,
  data?: tSelectDataItem[],

  wrapperEle?: HTMLElement,
  inputEle?: HTMLElement,
  listEle?: HTMLElement,
  resultEle?: HTMLElement,

  maxVisibleListItems?: number
}
Run Code Online (Sandbox Code Playgroud)

我宣布一个全局模块明智的变量:

var $protected : tSelectProtected = {};
Run Code Online (Sandbox Code Playgroud)

我在function1范围内分配了适当的值:

$protected.listEle = document.createElement('DIV');
Run Code Online (Sandbox Code Playgroud)

我稍后在function2范围内调用:

$protected.listEle.classList.add('visible');
Run Code Online (Sandbox Code Playgroud)

我收到TypeScript错误:

error TS2533: Object is possibly 'null' or 'undefined'
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用显式检查type来平息编译器,但对于大多数非平凡的情况,这似乎是非常不方便的.

如何在不禁用TS编译器检查的情况下处理这种情况?

Rya*_*ugh 494

如果从外部知道表达式不是null或者undefined,则可以使用非null断言运算符!来强制转换这些类型:

// Error, some.expr may be null or undefined
let x = some.expr.thing;
// OK
let y = some.expr!.thing;
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你让我知道`! - 非空断言运算符`运算符.似乎事情还没有很好的记录([https://github.com/Microsoft/TypeScript/issues/11494 ](https://github.com/Microsoft/TypeScript/issues/11494))所以任何人都在寻找答案阅读本文[http://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-method](http://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-方法) (9认同)
  • 这对tsc v2.7.2也没有影响 (7认同)
  • @ThomasSauvajon这里的`!`运算符*不*做与C#中```做同样的事情!它只是一个*类型系统*断言; 尝试从"null"或"undefined"读取属性时,它不会导致程序崩溃. (6认同)
  • 这在Typescript 3.2.2中不起作用.它被删除了吗? (4认同)
  • 我一般不会推荐这个。编译器告诉您它无法证明某些内容不为空。你告诉它“相信我,事实并非如此”。最好是让编译器真正相信某些东西不为空,而不是压制它的抱怨。 (3认同)
  • 在手册中,是Ryan的补充:_语法为后缀`!`:`identifier!`从`identifier`类型中删除`null`和`undefined`_这是Ryan已经说过的,但是我发现这种方式也很有用。 (2认同)
  • ?。= 如果它不为空,则将其链接起来!。= 这样做它绝对不是空的,如果它碰巧是空的,那我就完蛋了 (2认同)

Dou*_*las 75

此功能称为"严格空检查",将其关闭以确保--strictNullChecks未设置编译器标志.

然而,存在null已经被描述十亿美元的错误,所以这是令人兴奋地看到语言如打字稿引入一个修复.我强烈建议保持打开状态.

解决此问题的一种方法是确保值永远不会,null或者undefined例如通过预先初始化它们:

interface SelectProtected {
    readonly wrapperElement: HTMLDivElement;
    readonly inputElement: HTMLInputElement;
}

const selectProtected: SelectProtected = {
    wrapperElement: document.createElement("div"),
    inputElement: document.createElement("input")
};
Run Code Online (Sandbox Code Playgroud)

  • 在TS 2.7.2中,即使初始化也不能抑制"对象可能'未定义'" (15认同)
  • 我个人在"vanilla"JavaScript中使用`null`s来初始化变量或属性值.如果给定var或prop存在但是它具有"无可用值"或"在某个执行点清除了值",这给了我直接答案.按惯例来看.这可能不是TypeScript中的最佳方法,我可以通过这里的答案看到.谢谢你的想法. (6认同)
  • 如果你试图描述一些Javascript Object属性的状态,其中起始状态的真实表示是"null"怎么办? (4认同)

Van*_*esh 51

如果需要,您可以通过添加评论来抑制(注意以下)

// @ts-ignore: Object is possibly 'null'.

不是对 OP 问题的直接回答,而是在我的带有 Typescript 的 React 应用程序中 - v3.6.2
tslint -v5.20.0

并使用以下代码

const refToElement = useRef(null);

if (refToElement && refToElement.current) {
     refToElement.current.focus(); // Object is possibly 'null' (for refToElement.current)
}
Run Code Online (Sandbox Code Playgroud)

我通过抑制该行的编译器继续前进 -

const refToElement = useRef(null);

if (refToElement && refToElement.current) {
     // @ts-ignore: Object is possibly 'null'.
     refToElement.current.focus(); 
}
Run Code Online (Sandbox Code Playgroud)

警告

请注意,由于这是编译器错误而不是 linter 错误,// tslint:disable-next-line因此无效。此外,根据文档,这应该很少使用,仅在必要时使用

更新

从 Typescript 3.7 开始,您可以使用optional chaining来解决上述问题 -

refToElement?.current?.focus();
Run Code Online (Sandbox Code Playgroud)

此外,有时可能只是将适当的类型传递给泛型参数,而使用useRef.
例如:如果是input元素 -

const refToElement = useRef<HTMLInputElement>(null);
Run Code Online (Sandbox Code Playgroud)

  • 类型“never”上不存在属性“goBack”。ts(2339) (4认同)
  • 比禁用“strictNullChecks”更好的解决方案,应该谨慎使用,大多数时候您需要空引用错误,因为它可能会导致真正的麻烦。 (3认同)
  • 就我而言,这个可选链接不起作用。`const input = useRef&lt;HTMLInputElement&gt;(null);` 和 `if (input &amp;&amp; input.current) { input.current.value = ''; }` 成功了。 (3认同)
  • 属性“getBoundingClientRect”在类型“never”上不存在。 (2认同)

Blo*_*gic 28

要解决此问题,如果您确定在访问其属性时该对象不为空,则可以简单地使用感叹号:

list!.values
Run Code Online (Sandbox Code Playgroud)

乍一看,有些人可能会从角度上将其与安全导航操作符混淆,事实并非如此!

list?.values
Run Code Online (Sandbox Code Playgroud)

!后修复的表达会告诉编译器TS变量不为空,如果这是不是会在运行时崩溃的情况下

使用引用

对于useRef挂钩使用这样的

const value = inputRef?.current?.value
Run Code Online (Sandbox Code Playgroud)

  • 我想说这是正确的答案,尽管上面已经发布了。我认为建议改变消费者代码的答案是错误的。 (3认同)

Jos*_*ree 22

我用了:

if (object !== undefined) {
    // continue - error suppressed when used in this way.
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用类型强制:

const objectX = object as string
Run Code Online (Sandbox Code Playgroud)

虽然在选择上述解决方法之一之前,请考虑您的目标架构,并对整体情况产生影响.

  • 出于某种原因,我的TSC忽略了if语句,仍然认为它可能是未定义的...... (40认同)
  • 当我使用`if(object!== undefined)object.function();时,我的错误不会被抑制。 (5认同)
  • 也不会用最近的打字稿抑制我的错误。对于这种令人沮丧的行为有什么解决方法吗? (3认同)

Mah*_*pal 15

这个解决方案对我有用:

  • 转到tsconfig.json并添加"strictNullChecks":false

在此输入图像描述

  • 不回答这个问题.OP明确表示:'不禁用TS编译器检查' (22认同)
  • 使用TypeScript和消除linter错误的目的是要提醒您什么?我认为更好的选择是,如果您100%确定,则使用`as`转换所需的值。我遇到了mongodb和FindOneOrUpdate返回值的情况,我不得不将其强制转换为Schema,因为`result.value`被声明为`TSchema |。undefined`,而我之前已经检查过“ result.ok” (2认同)

小智 13

与“对象可能为空”编译错误相关,如果您想在打字稿配置中禁用此检查,您应该在文件中添加以下行tsconfig.json

"compilerOptions": {

   // other rules

   "strictNullChecks": false
}
Run Code Online (Sandbox Code Playgroud)

  • 关闭此功能不是一个好主意。该规则可以帮助您避免一类非常常见的类型错误。修复程序(调整类型并添加 if 检查)比消除烦人但有用的错误更好。 (4认同)
  • 关闭“strictNullChecks”不是解决方案。 (4认同)

ssu*_*ube 12

如果您知道类型将永远不会nullundefined,您应该声明它foo: Bar没有?.声明具有? Bar语法的类型意味着它可能未定义,这是您需要检查的内容.

换句话说,编译器正在完全按照您的要求进行操作.如果您希望它是可选的,您需要稍后检查.

  • “编译器正在做你要求它做的事情”所以我的想法是错误的,谢谢。我需要稍微改变一下方法。 (2认同)

thi*_*ber 8

这不是OP的问题,但是Object is possibly 'null'当我偶然将参数声明为null类型时,我收到了相同的消息:

something: null;
Run Code Online (Sandbox Code Playgroud)

而不是为其赋值null:

something: string = null;
Run Code Online (Sandbox Code Playgroud)

  • 这是实际答案。当您进行实际的显式null检查并仍然得到Object可能是'null'错误时,您会感到沮丧。这个答案解决了。 (2认同)

Jam*_*ber 7

对我来说,这是一个错误ref和反应:

const quoteElement = React.useRef()
const somethingElse = quoteElement!.current?.offsetHeight ?? 0
Run Code Online (Sandbox Code Playgroud)

这会抛出错误,修复,给它一个类型:

// <div> reference type
const divRef = React.useRef<HTMLDivElement>(null);

// <button> reference type
const buttonRef = React.useRef<HTMLButtonElement>(null);

// <br /> reference type
const brRef = React.useRef<HTMLBRElement>(null);

// <a> reference type
const linkRef = React.useRef<HTMLLinkElement>(null);
Run Code Online (Sandbox Code Playgroud)

没有更多的错误,希望在某种程度上这可能会帮助其他人,甚至我将来:P


She*_*tor 5

作为一种选择,您可以使用类型转换。如果您从打字稿中收到此错误,则意味着某些变量具有类型或未定义:

let a: string[] | undefined;

let b: number = a.length; // [ts] Object is possibly 'undefined'
let c: number = (a as string[]).length; // ok
Run Code Online (Sandbox Code Playgroud)

确保a代码中确实存在该代码。


Sim*_*ver 5

RxJS 的提示

我经常会拥有 类型的成员变量,并且直到(使用 Angular)Observable<string>我才会初始化它。ngOnInit然后编译器假设它未初始化,因为它没有“在构造函数中明确分配” - 并且编译器永远不会理解ngOnInit

您可以在定义上使用!断言运算符来避免错误:

favoriteColor!: Observable<string>;
Run Code Online (Sandbox Code Playgroud)

未初始化的可观察对象可能会导致各种运行时痛苦,并出现诸如“您必须提供流但提供了 null”之类的错误。!如果您确实知道它将被设置为类似 的值,那么就可以了,ngOnInit在某些情况下,该值可能会以其他不太确定的方式设置。

所以我有时会使用的另一种选择是:

public loaded$: Observable<boolean> = uninitialized('loaded');
Run Code Online (Sandbox Code Playgroud)

其中在uninitialized全局某处定义为:

export const uninitialized = (name: string) => throwError(name + ' not initialized');
Run Code Online (Sandbox Code Playgroud)

然后,如果您在未定义该流的情况下使用该流,它将立即引发运行时错误。


Ged*_*eon 5

在 ReactJS 中,我检查构造函数中变量是否为空,如果是,我将其视为异常并适当地管理异常。如果变量不为空,代码将继续执行,并且编译器在此之后不会再抱怨:

private variable1: any;
private variable2: any;

constructor(props: IProps) {
    super(props);

    // i.e. here I am trying to access an HTML element
    // which might be null if there is a typo in the name
    this.variable1 = document.querySelector('element1');
    this.variable2 = document.querySelector('element2');

    // check if objects are null
    if(!this.variable1 || !this.variable2) {
        // Manage the 'exception', show the user a message, etc.
    } else {
        // Interpreter should not complain from this point on
        // in any part of the file
        this.variable1.disabled = true; // i.e. this line should not show the error
    }
Run Code Online (Sandbox Code Playgroud)


Jon*_*ONT 5

从 TypeScript 3.7 ( https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html ) 开始,您现在可以?.在访问属性(或调用方法)时使用运算符来获取未定义) 在 null 或未定义的对象上:

inputEl?.current?.focus(); // skips the call when inputEl or inputEl.current is null or undefined
Run Code Online (Sandbox Code Playgroud)