我有一个 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 编译器检查的情况下如何或应该如何处理这种情况?
如果您从外部表示某个表达式不是 null
或 undefined
,则可以使用 non-null assertion operator !
强制移除这些类型:
// Error, some.expr may be null or undefined
let x = some.expr.thing;
// OK
let y = some.expr!.thing;
此功能称为“严格的空检查”,要关闭它,请确保未设置 --strictNullChecks
编译器标志。
但是,null
的存在将 been described 作为 The Billion Dollar Mistake,因此看到诸如 TypeScript 之类的语言引入修复程序是令人兴奋的。我强烈建议保持打开状态。
解决此问题的一种方法是确保值永远不会是 null
或 undefined
,例如通过预先初始化它们:
interface SelectProtected {
readonly wrapperElement: HTMLDivElement;
readonly inputElement: HTMLInputElement;
}
const selectProtected: SelectProtected = {
wrapperElement: document.createElement("div"),
inputElement: document.createElement("input")
};
不过,请参阅 Ryan Cavanaugh's answer 了解替代选项!
null
来初始化变量或属性值。如果给定的 var 或 prop 存在但它“没有可用值”或“值在某个执行点被清除”,这给了我直接的答案。这只是按照惯例。正如我在这里的答案所见,这可能不是 TypeScript 中的最佳方法。谢谢你的想法。
null
,该怎么办?
!
运算符,与 Kotlin 中的运算符非常相似,它可以让您使这些检查更加简洁
如果需要,您可以通过添加注释来抑制(下面有 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
更好的解决方案,应该谨慎使用它,大多数时候你想要空引用错误,因为它可能会导致真正的头痛。
const input = useRef<HTMLInputElement>(null);
和 if (input && input.current) { input.current.value = ''; }
成功了。
useRef<MyComponent>(null)
中指定组件类型,否则 TS 不知道引用也可以是 null
以外的其他内容。
更新:Object chaining 是一种访问可能为 null 或未定义的引用的属性的方法
object?.objectProperty?.nextProperty
之前
if (object !== undefined) {
// continue - error suppressed when used in this way.
}
之前
const objectX = object as string
虽然,在选择上述解决方法之一之前,请考虑您的目标架构及其对大局的影响。
if(object!==undefined) object.function();
时,我的错误没有被抑制
null
和 undefined
使用双重比较,这不是一个坏习惯(仅在使用这两种类型时) - 事件 TSLint 将允许您这样做。它简化了检查是否定义了某些内容,因为您可以只使用 null != someObject
而不是编写 null !== someObject && undefined !== someObject
this
!
这个解决方案对我有用:
转到 tsconfig.json 并添加“strictNullChecks”:false
https://i.stack.imgur.com/dfGCY.png
as
投射所需的值。我得到了 mongodb 和 FindOneOrUpdate 返回值的情况,我不得不将它转换为 Schema,因为 result.value
被声明为 TSchema | undefined
并且我之前已经检查过 result.ok
要解决此问题,如果您确定对象在访问其属性时不为空,则可以简单地使用感叹号:
list!.values
乍一看,有些人可能会将此与 angular 的安全导航运算符混淆,事实并非如此!
list?.values
!
后缀表达式将告诉 TS 编译器变量不为空,如果不是这样,它将在运行时崩溃
使用参考
useRef
像这样使用钩子
const value = inputRef?.current?.value
if(list.value){ console.log(list.value)}
这将告诉 TS 编译器只有当父条件通过时才会访问该值
如果您知道该类型永远不会是 null
或 undefined
,则应将其声明为 foo: Bar
而没有 ?
。使用 ? Bar
语法声明类型意味着它可能是未定义的,这是您需要检查的。
换句话说,编译器正在按照您的要求执行。如果您希望它是可选的,则需要稍后进行检查。
这不是 OP 的问题,但是当我意外地将参数声明为 null 类型时,我得到了相同的 Object is possibly 'null'
消息:
something: null;
而不是为其分配 null 值:
something: string = null;
Object is possibly 'null'
错误时,令人沮丧。这个答案解决了这个问题。
作为一个选项,您可以使用类型转换。如果您从打字稿中收到此错误,则表示某些变量具有类型或未定义:
let a: string[] | undefined;
let b: number = a.length; // [ts] Object is possibly 'undefined'
let c: number = (a as string[]).length; // ok
确保您的代码中确实存在 a
。
any
。而是将其转换为显式类型。如果您使用 any
,您首先会错过使用 TypeScript 的意义。
document.querySelector()
是为了抑制 null 可能性而进行强制转换的一个实际示例,因为该元素可能不存在。我今天遇到了这个确切的问题,我知道在每个 .
之前添加 !
并不是唯一的解决方案。感谢您为我节省了阅读文档的时间(尽管我可能会在有时间的时候阅读它们)
对我来说,这是 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
。附加类型是可选的。
与“object is possible null”相关的编译错误,如果您想在您的 typescript 配置中禁用此检查,您应该在 tsconfig.json
文件中添加以下行。
"compilerOptions": {
// other rules
"strictNullChecks": false
}
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');
然后,如果您在未定义的情况下使用此流,它将立即引发运行时错误。
在 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
}
从 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
?.
。
// @ts-nocheck
将此添加到文件顶部
https://i.stack.imgur.com/1moSo.png
在设置状态和使用 map
时,我使用 React 遇到了这个问题。
在这种情况下,我正在进行 API 提取调用,响应的值未知,但 应该 有一个值“Answer”。我为此使用了自定义类型,但因为该值可能是 null
,我还是得到了一个 TS 错误。允许类型为 null
并不能解决问题;或者,您可以使用 default parameter value
,但这对我来说很麻烦。
我通过仅使用三元运算符在响应为空的情况下提供默认值来克服它:
this.setState({ record: (response.Answer) ? response.Answer : [{ default: 'default' }] });
尝试像这样调用对象:
(<any>Object).dosomething
出现此错误是因为您已使用 ?
将它们声明为可选。现在 Typescript 做了严格的检查,它不允许做任何可能是 undefined
的事情。因此,您可以在此处使用 (<any>yourObject)
。
在打字稿中,您可以执行以下操作来抑制 error
:
let subString?: string;
subString > !null;
- 注意在 null 之前添加的感叹号。
这不是 OP 的答案,但我看到很多人对如何在评论中避免这个错误感到困惑。这是通过编译器检查的简单方法
if (typeof(object) !== 'undefined') {
// your code
}
注意:这不起作用
if (object !== undefined) {
// your code
}
这相当冗长,不喜欢它,但它是唯一对我有用的东西:
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 和推荐的规则。
您可以在以下情况下使用类型转换:
// `textarea` is guaranteed to be loaded
const textarea = <HTMLTextAreaElement>document.querySelector('textarea')
👇 no error here
textarea.value = 'foo'
querySelector()
未找到该控件,它仍可能未定义或为空。
很惊讶没有人回答这个问题,您所要做的就是在访问对象之前检查对象是否存在,这非常简单。否则,请确保在访问对象之前初始化您的值。
if($protected.listEle.classList) { $protected.listEle.classList.add('visible'); }
像这样绑定你的变量 variabalName?.value
它肯定会工作。
Property 'value' does not exist on type 'never'.
不是 OPs 问题,但我通过添加空检查解决了这个问题
我变了:
*ngIf="username.invalid && username.errors.required"
至
*ngIf="username.invalid && username.errors != null && username.errors.required"
在角度,我使用:
// 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 的原因。
当我在 tsconfig.json 文件中将“strict:true”更改为“strict:false”时,代码没有显示错误。添加添加!像添加的 obj 一样签名
myImage!.getAttriute('src');
比代码没有显示错误。
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
我在使用 Angular (11.x) 时遇到了这个问题。在前一天,我将一段 HTML/组件移到了一个单独的 - 较小的 - 组件中。第二天我的电脑关闭了,我的项目无法构建。事实证明,组件 .html 是问题所在。如前所述,这是零安全性...
从此(摘录):
<div class="code mat-body-strong">{{ machine.productCode }}</div>
对此:
<div class="code mat-body-strong">{{ machine?.productCode }}</div>
在打字稿中,要静音有关可能性为空的消息:
Interface {
data: string|null
}
const myData = document.data ?? "";
! - Non-null assertion operator
运算符。似乎这件事还没有很好的记录(https://github.com/Microsoft/TypeScript/issues/11494)所以任何寻找答案的人都会阅读这个http://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-method!
运算符 not 与 C# 中的?
执行相同的操作!它只是一个类型系统断言;它不会导致您的程序在尝试从null
或undefined
读取属性时不会崩溃。!
:identifier!
从identifier
的类型中删除null
和undefined
这是 Ryan 已经说过的,但我发现这种方式也很有帮助。