ChatGPT解决这个技术问题 Extra ChatGPT

如何抑制“错误 TS2533:对象可能是‘空’或‘未定义’”?

我有一个 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 编译器检查的情况下如何或应该如何处理这种情况?


W
Willem Renzema

如果您从外部表示某个表达式不是 nullundefined,则可以使用 non-null assertion operator ! 强制移除这些类型:

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

感谢您让我了解 ! - Non-null assertion operator 运算符。似乎这件事还没有很好的记录(https://github.com/Microsoft/TypeScript/issues/11494)所以任何寻找答案的人都会阅读这个http://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-method
这对我在 tsc v2.7.2 上也没有影响
@ThomasSauvajon 此处的 ! 运算符 not 与 C# 中的 ? 执行相同的操作!它只是一个类型系统断言;它不会导致您的程序在尝试从 nullundefined 读取属性时不会崩溃。
来自手册,在 Ryan 的刺激下添加:语法是后缀 !identifier!identifier 的类型中删除 nullundefined 这是 Ryan 已经说过的,但我发现这种方式也很有帮助。
这在 Typescript 3.2.2 中不起作用。它被删除了吗?
V
Vlad Topala

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

但是,null 的存在将 been described 作为 The Billion Dollar Mistake,因此看到诸如 TypeScript 之类的语言引入修复程序是令人兴奋的。我强烈建议保持打开状态。

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

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

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

不过,请参阅 Ryan Cavanaugh's answer 了解替代选项!


我个人在“vanilla”JavaScript 中使用 null 来初始化变量或属性值。如果给定的 var 或 prop 存在但它“没有可用值”或“值在某个执行点被清除”,这给了我直接的答案。这只是按照惯例。正如我在这里的答案所见,这可能不是 TypeScript 中的最佳方法。谢谢你的想法。
在 TS 2.7.2 中,即使初始化也不会抑制“对象可能是'未定义'”
是的,但是这些定义会改变对象的值,例如,HTMLDivElement 没有最近的目标和其他基本元素事件和属性。
如果您试图描述某个 Javascript 对象属性的状态,其中起始状态的真实表示是 null,该怎么办?
补充说,有一个可用的 ! 运算符,与 Kotlin 中的运算符非常相似,它可以让您使这些检查更加简洁
V
Vandesh

如果需要,您可以通过添加注释来抑制(下面有 CAUTION)

// @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)
}

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

const refToElement = useRef(null);

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

警告

请注意,由于它是编译器错误而不是 linter 错误,因此 // tslint:disable-next-line 不起作用。另外,as per the documentation, this should be used rarely, only when necessary

更新

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

refToElement?.current?.focus();

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

const refToElement = useRef<HTMLInputElement>(null);

比禁用 strictNullChecks 更好的解决方案,应该谨慎使用它,大多数时候你想要空引用错误,因为它可能会导致真正的头痛。
“从不”类型上不存在属性“getBoundingClientRect”。
在我的情况下,这个可选链接不起作用。 const input = useRef<HTMLInputElement>(null);if (input && input.current) { input.current.value = ''; } 成功了。
类型“从不”.ts(2339) 上不存在属性“goBack”
您需要在 useRef<MyComponent>(null) 中指定组件类型,否则 TS 不知道引用也可以是 null 以外的其他内容。
J
JoshuaTree

更新:Object chaining 是一种访问可能为 null 或未定义的引用的属性的方法

object?.objectProperty?.nextProperty

之前

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

之前

const objectX = object as string

虽然,在选择上述解决方法之一之前,请考虑您的目标架构及其对大局的影响。


出于某种原因,我的 TSC 忽略了 if 语句,仍然认为它可能是未定义的......
当我使用 if(object!==undefined) object.function(); 时,我的错误没有被抑制
也可以对 nullundefined 使用双重比较,这不是一个坏习惯(仅在使用这两种类型时) - 事件 TSLint 将允许您这样做。它简化了检查是否定义了某些内容,因为您可以只使用 null != someObject 而不是编写 null !== someObject && undefined !== someObject
也不会用最近的打字稿来抑制我的错误。这种令人沮丧的行为有什么解决方法吗?
检查似乎没有抑制我的警告,这里涉及的对象是 this
M
Mahesh Nepal

这个解决方案对我有用:

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

https://i.stack.imgur.com/dfGCY.png


这也对我有用。尽管它仍然给出错误,例如在订阅语句中,它没有识别结果变量,打字稿希望它声明 .subscribe(result => this.result =result.json());
您是否尝试过使用“地图”运算符?谷歌“rxjs/地图”。我基本上是这样的:。 Http.get(...).map(result => result.json()).subscribe(result=>{在这里做你的事情})
不回答问题。 OP 明确表示:'不禁用 TS 编译器检查'
使用 TypeScript 并消除 linter 错误有什么意义?如果您 100% 确定,我认为更好的选择是使用 as 投射所需的值。我得到了 mongodb 和 FindOneOrUpdate 返回值的情况,我不得不将它转换为 Schema,因为 result.value 被声明为 TSchema | undefined 并且我之前已经检查过 result.ok
@Vincent 的重点是在您的 IDE 中实现智能自动完成,同时仍保留 JavaScript 的一些动态特性。
E
Ericgit

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

list!.values

乍一看,有些人可能会将此与 angular 的安全导航运算符混淆,事实并非如此!

list?.values

! 后缀表达式将告诉 TS 编译器变量不为空,如果不是这样,它将在运行时崩溃

使用参考

useRef 像这样使用钩子

const value = inputRef?.current?.value

我会说这是正确的答案,尽管上面已经发布了。我认为建议更改消费者代码的答案是错误的。
上面可能会在运行时崩溃,最好检查一下,if(list.value){ console.log(list.value)} 这将告诉 TS 编译器只有当父条件通过时才会访问该值
s
ssube

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

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


“编译器正在按照你的要求做”所以我的想法是错误的,谢谢。我需要稍微改变一下方法。
在我的情况下,编译器根本没有意识到我已经检查了对象是否为空。我有一个 getter 来检查 null 并调用该 getter。所以不,它并没有完全按照我的要求去做(这并不是说我希望它能够解决所有问题)。
t
thinkOfaNumber

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

something: null;

而不是为其分配 null 值:

something: string = null;

这是实际的答案。当您进行实际的显式空检查并且仍然得到 Object is possibly 'null' 错误时,令人沮丧。这个答案解决了这个问题。
S
Shevchenko Viktor

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

let a: string[] | undefined;

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

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


这对我来说是可行的解决方案。在“on fly”界面中将该成员声明为“any”类型已解决了问题
@BoteaFlorin 您不应该将其转换为 any。而是将其转换为显式类型。如果您使用 any,您首先会错过使用 TypeScript 的意义。
document.querySelector() 是为了抑制 null 可能性而进行强制转换的一个实际示例,因为该元素可能不存在。我今天遇到了这个确切的问题,我知道在每个 . 之前添加 ! 并不是唯一的解决方案。感谢您为我节省了阅读文档的时间(尽管我可能会在有时间的时候阅读它们)
@AhmedShaqanbi 这不是一个很好的例子。您仍然应该检查或使用选项链接。如果编译器认为某些东西可能为空,那么它真的很可能是,你应该在假设下编写代码。
J
Jamie Hutber

对我来说,这是 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


实际上,修复只是将 null 传递给 useRef。附加类型是可选的。
M
Mehdi Roostaeian

与“object is possible null”相关的编译错误,如果您想在您的 typescript 配置中禁用此检查,您应该在 tsconfig.json 文件中添加以下行。

"compilerOptions": {

   // other rules

   "strictNullChecks": false
}

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

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 参数
G
Gedeon

在 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
    }

J
Jonathan Cast CONT

从 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

可选的属性访问运算符是 ?.
S
Santosh nayak
// @ts-nocheck

将此添加到文件顶部

https://i.stack.imgur.com/1moSo.png


在代码中使用 Typescript 并关闭 Typescript 并不是一个好主意。那你不妨使用Javascript。
是的我同意。但这暂时可以快速解决
C
Chris Shaffer

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

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

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

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

P
Pedro Mutter

尝试像这样调用对象:

(<any>Object).dosomething

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


P
Philipp Meissner

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

let subString?: string;

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


J
Joe

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

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

注意:这不起作用

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

即使在支票内,它仍然会抱怨。
m
mosu

这相当冗长,不喜欢它,但它是唯一对我有用的东西:

if (inputFile && inputFile.current) {
        ((inputFile.current as never) as HTMLInputElement).click()
}

只要

if (inputFile && inputFile.current) {
        inputFile.current.click() // also with ! or ? didn't work
}

对我不起作用。 Typesript 版本:3.9.7,带有 eslint 和推荐的规则。


是的!在这种情况下,这是最好的解决方案。谢谢你。
W
Wenfang Du

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

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

如果 querySelector() 未找到该控件,它仍可能未定义或为空。
A
Ahmad Khudeish

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

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


V
Vibhu kumar

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


它会产生另一个错误 Property 'value' does not exist on type 'never'.
N
Nick

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

我变了:

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

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

S
Shmarkus

在角度,我使用:

// 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 的原因。


这也只是隐藏错误而不是修复它。
M
Mudassar Mustafai

当我在 tsconfig.json 文件中将“strict:true”更改为“strict:false”时,代码没有显示错误。添加添加!像添加的 obj 一样签名

myImage!.getAttriute('src');

比代码没有显示错误。


这并不能修复错误,它只是将其关闭。
E
Emanuel
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>

https://i.stack.imgur.com/TaKcK.png


O
O-9

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

从此(摘录):

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

对此:

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


d
dawid debinski

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

Interface   {
  data: string|null
}

const myData = document.data ?? "";