如何抑制“错误TS2533:对象可能为'null'或'undefined'”?


225

我有一个type

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编译器检查的情况下处理这种情况?

Answers:


99

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

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

解决此问题的一种方法是确保值从不为nullundefined(例如,通过预先初始化):

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

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

不过,请参阅Ryan Cavanaugh的答案以寻求替代选择!


8
我个人null在“普通” JavaScript中使用s来初始化变量或属性值。如果给定的var或prop存在但它“尚无可用值”或“执行时已清除值”,这将给我直接的答案。只是按照惯例。正如我在此处的答案所示,这可能不是TypeScript中的最佳方法。谢谢你的想法。
2002年

25
在TS 2.7.2中,即使初始化也不能抑制“对象可能是'undefined'”
Tyguy7 '18

1
是的,但是这些定义会更改对象的值,例如,HTMLDivElement没有最接近的目标以及其他基本元素事件和属性。
克拉伦斯

5
如果您试图描述某些Javascript对象属性的状态,而起始状态的真实表示是null怎么办?
Timur Mamedov '18

1
此外,还有一个!可用的运算符,与Kotlin中的运算符非常相似,您可以使这些检查更加简洁
Alvaro19年

598

如果您从外部方法中知道某个表达式不是nullor undefined,则可以使用非null断言运算符!强制转换这些类型:

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

12
感谢您让我知道! - Non-null assertion operator运算符。似乎尚未对此文件进行充分的记录(https://github.com/Microsoft/TypeScript/issues/11494),因此任何寻求答案的人都可以阅读此http://stackoverflow.com/questions/38874928/operator-in-typescript -after-object-method
grasnal

9
这对我在tsc v2.7.2上也没有影响
Tyguy7 '18

6
@ThomasSauvajon !这里的运算符不会执行与?C#中相同的操作!它只是一个类型系统断言。尝试从null或读取属性时,它不会导致程序不会崩溃undefined
Ryan Cavanaugh

2
从手册开始,在Ryan的提议中添加: 语法为postfix !:从identifier!nullundefinedidentifier Ryan 的类型中删除从类型中删除但这对Ryan也很有帮助。
约翰·哈顿

5
这在Typescript 3.2.2中不起作用。它被删除了吗?
拉尔斯·尼斯特罗姆(LarsNyström),

25

我用了:

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

另外,您可以使用强制类型:

const objectX = object as string

尽管在选择上述解决方法之一之前,请先考虑您要使用的体系结构,它会影响整体。


57
由于某种原因,我的TSC忽略了if语句,仍然认为它可能是未定义的……
Tyguy7 '18

9
使用时不会阻止我的错误if(object!==undefined) object.function();
杰里米

你也可以使用双比较nullundefined,这是不是一个不好的做法(只有当与这两种类型使用) -事件TSLint将允许你这样做。它简化了检查,如果事情被定义的,因为,而不是写null !== someObject && undefined !== someObject,你可以只使用null != someObject
Marecky

14

不是直接回答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因此无法正常工作。此外,根据文档,应仅在必要时很少使用它 -

const refToElement = useRef(null);

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

更新

使用Typescript 3.7,您可以使用可选的chaining来解决上述问题,方法是-

refToElement?.current?.focus();

2
比禁用更好的解决方案strictNullChecks是,在大多数情况下,您需要使用空引用错误,因为这可能会导致真正的头痛,因此应谨慎使用。
安迪·布拉汉姆

类型“从不”上不存在属性“ getBoundingClientRect”。
mqliutie

在我的情况下,此可选链接无效。const input = useRef<HTMLInputElement>(null);if (input && input.current) { input.current.value = ''; }做到了。
Timo

13

此解决方案为我工作:

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

在此处输入图片说明


这也为我工作。尽管它仍然发出错误,例如在订阅语句中,但它无法识别结果变量,但打字稿希望它声明.subscribe(result => this.result = result.json());。
Aarchie

您是否尝试过使用“地图”运算符?Google'rxjs / map'。我基本上是这样:Http.get(...)。map(result => result.json())。subscribe(result => {在这里做你的东西})
Mahesh尼泊尔

38
没有回答问题。OP明确表示:“不禁用TS编译器检查”
pvill

4
使用TypeScript和消除linter错误的目的是要提醒您什么?我认为更好的选择是,as如果您100%确信,则使用所需的值。我得到的MongoDB和FindOneOrUpdate返回值的情况下,我不得不因为它转换为架构result.value声明为TSchema | undefined和我已经已经检查result.ok
文森特

12

如果您知道类型永远不会是nullundefined,则应将其声明为foo: Bar不带?。使用? Bar语法声明类型意味着可能未定义它,这是您需要检查的事情。

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


1
“编译器完全按照您的要求进行操作”,所以我的想法是错误的,谢谢。我需要稍微改变一下方法。
grasnal,2016年

就我而言,编译器根本没有意识到我已经检查了该对象是否为null。我有一个检查null的吸气剂,然后调用该吸气剂。因此,不,它并没有完全按照我的要求(并不是说我希望它能够解决所有问题)来做。
CWagner '19

9

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

something: null;

而不是为其分配null值:

something: string = null;

2
这是实际答案。当您执行实际的显式null检查并仍然收到Object is possibly 'null'错误时,这令人沮丧。这个答案解决了。
Ben Racicot

5

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

let a: string[] | undefined;

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

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



2

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

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


我不建议在任何地方都这样做,但是有时我会这样做-特别是如果依赖于从外部设置的@Input参数
Simon_Weaver

2

在ReactJS中,我检查构造函数中的变量是否为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
    }

1

设置状态和使用时,我遇到了React map

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

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

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

0

在打字稿中,您可以执行以下操作来消除error

let subString?: string;

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


0

尝试这样调用对象:

(<any>Object).dosomething

发生此错误是因为您已使用声明了它们为可选?。现在Typescript进行严格检查,不允许做任何可能的事情undefined。因此,您可以(<any>yourObject)在这里使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.