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

时间:2016-10-31 20:22:21

标签: typescript

我有一个类型:

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

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

  maxVisibleListItems?: number
}

我声明了一个全局模块明智的变量:

var $protected : tSelectProtected = {};

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

$protected.listEle = document.createElement('DIV');

我稍后在function2范围内调用:

$protected.listEle.classList.add('visible');

我收到TypeScript错误:

error TS2533: Object is possibly 'null' or 'undefined'

我知道我可以使用if ($protected.listEle) {$protected.listEle}进行明确检查以平息编译器,但对于大多数非平凡的案例来说,这似乎是非常不方便的。

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

27 个答案:

答案 0 :(得分:371)

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

// Error, some.expr may be null or undefined
let x = some.expr.thing;
// OK
let y = some.expr!.thing;

答案 1 :(得分:42)

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

但是,null的存在时been describedThe Billion Dollar Mistake,因此看到TypeScript等语言引入修复程序令人兴奋。我强烈建议保持打开状态。

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

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

const selectProtected: SelectProtected = {
    wrapperElement: document.createElement("div"),
    inputElement: document.createElement("input")
};

答案 2 :(得分:16)

我用过:

Resource leak: 'context' is never closed

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

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

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

答案 3 :(得分:14)

要解决此问题,如果在访问对象的属性时确定该对象不为null,则只需使用感叹号即可:

eatableFillColor(id)
{
  if (some_condition)
  {
    return "white";
  }
  return "black";
}

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

const MyCom = () => {

  //do something here. ex, open gallery to upload image, zoon in image in 

  useEffect(() => {
    // Component Did Mount

    return => {
      // ComponentWillUnmount
    }
  },[])

  return(/*Component*/)
}

list!.values 后缀表达式将告诉TS编译器变量不为null,否则变量将在运行时崩溃

useRef

用于list?.values 钩子这样使用

!

答案 4 :(得分:9)

如果您知道该类型永远不会是a()null,则应在没有undefined的情况下将其声明为foo: Bar。声明具有?语法的类型意味着它可能未定义,这是您需要检查的内容。

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

答案 5 :(得分:6)

这个解决方案对我有用:

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

enter image description here

答案 6 :(得分:6)

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

something: null;

而不是为其赋值null:

something: string = null;

答案 7 :(得分:4)

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

let a: string[] | undefined;

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

请确保您的代码中确实存在a

答案 8 :(得分:4)

不是OP的问题的直接答案,但就我而言,我具有以下设置-

打字稿-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)
}

我继续取消了该行的编译器。请注意,由于这是编译器错误,而不是linter错误,因此// tslint:disable-next-line不起作用。另外,as per the documentation, this should be used rarely, only when necessary-

const refToElement = useRef(null);

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

答案 9 :(得分:1)

从TypeScript 3.7(https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html开始,现在您可以使用public class Video { private FFmpegFrameGrabber grabber; private final static Java2DFrameConverter converter = new Java2DFrameConverter(); public Video(File file) { this.grabber = new FFmpegFrameGrabber(file); try { this.grabber.start(); } catch (Exception e) { e.printStackTrace(); } } public BufferedImage grabFrame(int framePos) throws Exception { BufferedImage frame; grabber.grabImage(); // Without this done before, the image is just black grabber.setFrameNumber(framePos); frame = converter.convert(grabber.grabImage()); return frame; } } 运算符在访问null或未定义对象上的属性(或调用方法)时得到未定义:

?.

答案 10 :(得分:1)

这不是OP的答案,但我看到很多人对如何避免注释中的错误感到困惑。这是通过编译器检查的简单方法

if (typeof(object) !== 'undefined') {
    // your code
}

注意: 这是行不通的

if (object !== undefined) {
        // your code
    }

答案 11 :(得分:1)

尝试这样调用对象:

(<any>Object).dosomething

之所以出现此错误,是因为您已使用?将它们声明为可选的。现在,Typescript会进行严格检查,并且不允许做任何可能undefined的事情。因此,您可以在此处使用(<any>yourObject)

答案 12 :(得分:1)

在ReactJS中,我检查构造函数中的变量是否为null,是否将它们视为异常,并适当地管理该异常。如果变量不为null,则代码会继续执行,并且编译器在此之后不再发出错误消息:

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
    }

答案 13 :(得分:0)

如果您在React中使用refs遇到此问题,则严格的null检查就足够了:

if (inputEl && inputEl.current) {
     inputEl.current.focus();
}

更多here

答案 14 :(得分:0)

设置状态并使用map时,我用React遇到了这个问题。

在这种情况下,我正在进行API提取调用,并且响应的值未知,但是应该的值为“ Answer”。我为此使用了自定义类型,但是由于该值可能为null,所以我还是遇到了TS错误。允许类型为null并不能解决问题;或者,您可以使用default parameter value,但这对我来说很麻烦。

在仅使用三元运算符的情况下响应为空的情况下,我通过提供默认值来克服它:

this.setState({ record: (response.Answer) ? response.Answer : [{ default: 'default' }] });

答案 15 :(得分:0)

RxJS提示

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

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

favoriteColor!: Observable<string>;

未初始化的observable可能导致各种运行时痛苦,并出现诸如“您必须提供流但您提供null”之类的错误。如果您肯定地知道将以!之类的方式进行设置,那么ngOnInit很好,但是在某些情况下,该值可以通过其他一些不确定性的方式来设置。

所以我有时会使用的替代方法是:

public loaded$: Observable<boolean> = uninitialized('loaded');

uninitialized全局定义为:

export const uninitialized = (name: string) => throwError(name + ' not initialized');

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

答案 16 :(得分:0)

在打字稿中,您可以执行以下操作以禁止显示error

let subString?: string;

subString > !null;-注意在null之前添加的感叹号。

答案 17 :(得分:0)

import React, { useRef, useState } from 'react'
...
const inputRef = useRef()
....
function chooseFile() {
  const { current } = inputRef
  (current || { click: () => {}}).click()
}
...
<input
   onChange={e => {
     setFile(e.target.files)
    }}
   id="select-file"
   type="file"
   ref={inputRef}
/>
<Button onClick={chooseFile} shadow icon="/upload.svg">
   Choose file
</Button>

使用next.js对我有用的唯一代码 enter image description here

答案 18 :(得分:0)

对我来说,ref出错并做出反应:

const quoteElement = React.useRef() const somethingElse = quoteElement!.current?.offsetHeight ?? 0

这将引发错误(即修复程序),并为其提供类型:

// <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);

没有更多的错误,希望以某种方式对其他人甚至将来对我有帮助:P

答案 19 :(得分:0)

我在使用 Angular (11.x) 时遇到了这个问题。在前一天,我将一段 HTML/组件移到了一个单独的(较小的)组件中。第二天,我的电脑关机了,我的项目无法构建。 事实证明,组件 .html 是问题所在。如前所述,这是零安全...

从此(摘录):

<div class="code mat-body-strong">{{ machine.productCode }}</div>

为此:

<div class="code mat-body-strong">{{ machine?.productCode }}</div>

答案 20 :(得分:0)

在打字稿中,将有关可能性为 null 的消息静音:

Interface   {
  data: string|null
}

const myData = document.data ?? "";

答案 21 :(得分:0)

您可以在以下情况下使用类型转换:

// `textarea` is guaranteed to be loaded
const textarea = <HTMLTextAreaElement>document.querySelector('textarea')
? no error here
textarea.value = 'foo'

答案 22 :(得分:0)

// @ts-nocheck

将此添加到文件顶部

enter image description here

答案 23 :(得分:0)

很惊讶没有人回答这个问题,您所要做的就是在访问对象之前检查对象是否存在,这非常简单。否则,请确保在访问对象之前初始化您的值。

if($protected.listEle.classList) {
   $protected.listEle.classList.add('visible');
}

答案 24 :(得分:0)

不是 OP 问题,但我通过添加空检查解决了这个问题

我改变了:

*ngIf="username.invalid &&  username.errors.required"

*ngIf="username.invalid && username.errors != null && username.errors.required"

答案 25 :(得分:0)

像这样绑定你的变量 variabalName?.value 它肯定会起作用。

答案 26 :(得分:0)

在角度,我使用:

// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
const sum = row
    .filter(p => p.priceInCents !== undefined)
    .reduce((sum, current) => sum + current.priceInCents, 0);

由于只是使用@ts-ignore,eslint 会抱怨它禁用了编译错误,这就是我添加 eslint-disable-next-line 的原因。