I have a type
:
type tSelectProtected = {
handleSelector?: string,
data?: tSelectDataItem[],
wrapperEle?: HTMLElement,
inputEle?: HTMLElement,
listEle?: HTMLElement,
resultEle?: HTMLElement,
maxVisibleListItems?: number
}
I declare a global module-wise variable:
var $protected : tSelectProtected = {};
I'm assigning proper value in function1()
scope:
$protected.listEle = document.createElement('DIV');
Later in function2()
scope, I'm calling:
$protected.listEle.classList.add('visible');
I'm getting TypeScript error:
error TS2533: Object is possibly 'null' or 'undefined'
I know that I can do explicit check using if ($protected.listEle) {$protected.listEle}
to calm down compiler but this seems to be very unhandy for most non trivial cases.
How this situation can or should be handled without disabling TS compiler checks?
If you know from external means that an expression is not null
or undefined
, you can use the non-null assertion operator !
to coerce away those types:
// Error, some.expr may be null or undefined
let x = some.expr.thing;
// OK
let y = some.expr!.thing;
This feature is called "strict null checks", to turn it off ensure that the --strictNullChecks
compiler flag is not set.
However, the existence of null
has been described as The Billion Dollar Mistake, so it is exciting to see languages such as TypeScript introducing a fix. I'd strongly recommend keeping it turned on.
One way to fix this is to ensure that the values are never null
or undefined
, for example by initialising them up front:
interface SelectProtected {
readonly wrapperElement: HTMLDivElement;
readonly inputElement: HTMLInputElement;
}
const selectProtected: SelectProtected = {
wrapperElement: document.createElement("div"),
inputElement: document.createElement("input")
};
See Ryan Cavanaugh's answer for an alternative option, though!
null
s in "vanilla" JavaScript to initialize variables or properties values. This gives me straight answer if given var or prop exists but it has "no usable value" yet or "value was cleared at some point of execution". It's just by convention. This may be not a best approach in TypeScript as I can see by answers here. Thank you for your thoughts.
null
?
!
operator available, very similar to the ones in Kotlin that lets you make these checks much more concise
You can suppress if needed, by adding a comment (with CAUTION below)
// @ts-ignore: Object is possibly 'null'.
Not a direct answer to the OP's question, but in my React application with Typescript - v3.6.2
tslint - v5.20.0
And using the following code
const refToElement = useRef(null);
if (refToElement && refToElement.current) {
refToElement.current.focus(); // Object is possibly 'null' (for refToElement.current)
}
I moved on by suppressing the compiler for that line -
const refToElement = useRef(null);
if (refToElement && refToElement.current) {
// @ts-ignore: Object is possibly 'null'.
refToElement.current.focus();
}
CAUTION
Note that since it's a compiler error and not the linter error, // tslint:disable-next-line
didn't work. Also, as per the documentation, this should be used rarely, only when necessary
UPDATE
With Typescript 3.7 onwards, you can use optional chaining, to solve the above problem as -
refToElement?.current?.focus();
Also, sometimes it just might be a matter of passing in the appropriate type to the generic paramenter, while using useRef
.
Eg: In case of an input
element -
const refToElement = useRef<HTMLInputElement>(null);
strictNullChecks
, caution should be used with this, most of the time you want the null reference error because it can cause real headaches down the road.
const input = useRef<HTMLInputElement>(null);
and if (input && input.current) { input.current.value = ''; }
did the trick.
useRef<MyComponent>(null)
, otherwise TS doesn't know that the reference can also be something else than null
.
Update: Object chaining is a means to access properties on possibly null or undefined reference
object?.objectProperty?.nextProperty
Previously
if (object !== undefined) {
// continue - error suppressed when used in this way.
}
Previously
const objectX = object as string
Although, before choosing one of the above workarounds, please consider the architecture you are aiming for and it's impact to the bigger picture.
if(object!==undefined) object.function();
null
and undefined
, and it is not a bad practice (only if using with those two types) - event TSLint will allow you to do it. It eases checking if something is defined because instead of writing null !== someObject && undefined !== someObject
you can use just null != someObject
this
!
This solution worked for me:
go to tsconfig.json and add "strictNullChecks":false
https://i.stack.imgur.com/dfGCY.png
as
if you 100% sure. I got the case with mongodb and FindOneOrUpdate return value and I had to cast it to the Schema because the result.value
is declared as TSchema | undefined
and I've already check with result.ok
before
To fix this you can simply use the exclamation mark if you're sure that the object is not null when accessing its property:
list!.values
At first sight, some people might confuse this with the safe navigation operator from angular, this is not the case!
list?.values
The !
post-fix expression will tell the TS compiler that variable is not null, if that's not the case it will crash at runtime
useRef
for useRef
hook use like this
const value = inputRef?.current?.value
if(list.value){ console.log(list.value)}
this would tell the TS compiler that the value will be accessed only if the parent condition passed
If you know the type will never be null
or undefined
, you should declare it as foo: Bar
without the ?
. Declaring a type with the ? Bar
syntax means it could potentially be undefined, which is something you need to check for.
In other words, the compiler is doing exactly what you're asking it to. If you want it to be optional, you'll need to the check later.
This is not the OP's problem, but I got the same Object is possibly 'null'
message when I had declared a parameter as the null type by accident:
something: null;
instead of assigning it the value of null:
something: string = null;
Object is possibly 'null'
error. This answer solves that.
As an option, you can use a type casting. If you have this error from typescript that means that some variable has type or is undefined:
let a: string[] | undefined;
let b: number = a.length; // [ts] Object is possibly 'undefined'
let c: number = (a as string[]).length; // ok
Be sure that a
really exist in your code.
any
. Instead cast it to an explicit type. If you use any
you miss the point of using TypeScript in the first place.
document.querySelector()
since it is possible that the element doesn't exist. I had this exact problem today and I knew that adding !
before every .
wasn't the only solution. Thanks for saving me minutes of reading the docs (even though I might read them when I have time)
For me this was an error with the ref
and react:
const quoteElement = React.useRef()
const somethingElse = quoteElement!.current?.offsetHeight ?? 0
This would throw the error, the fix, to give it a type:
// <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);
No more errors, hopefully in some way this might help somebody else, or even me in the future :P
null
to useRef
. The additional type is optional.
Related to 'object is possibly null' compile error, if you want to disable this checking in your typescript configuration, you should add the below line in the tsconfig.json
file.
"compilerOptions": {
// other rules
"strictNullChecks": false
}
Tip for RxJS
I'll often have member variables of type Observable<string>
, and I won't be initializing it until ngOnInit
(using Angular). The compiler then assumes it to be uninitialized becasue it isn't 'definitely assigned in the constructor' - and the compiler is never going to understand ngOnInit
.
You can use the !
assertion operator on the definition to avoid the error:
favoriteColor!: Observable<string>;
An uninitialized observable can cause all kinds of runtime pain with errors like 'you must provide a stream but you provided null'. The !
is fine if you definitely know it's going to be set in something like ngOnInit
, but there may be cases where the value is set in some other less deterministic way.
So an alternative I'll sometimes use is :
public loaded$: Observable<boolean> = uninitialized('loaded');
Where uninitialized
is defined globally somewhere as:
export const uninitialized = (name: string) => throwError(name + ' not initialized');
Then if you ever use this stream without it being defined it will immediately throw a runtime error.
In ReactJS, I check in the constructor if the variables are null, if they are I treat it like an exception and manage the exception appropriately. If the variables are not null, code carries on and compiler does not complain anymore after that point:
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
}
As of TypeScript 3.7 (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html), you can now use the ?.
operator to get undefined when accessing an attribute (or calling a method) on a null or undefined object:
inputEl?.current?.focus(); // skips the call when inputEl or inputEl.current is null or undefined
?.
.
// @ts-nocheck
Add this to the top of the file
https://i.stack.imgur.com/1moSo.png
I ran in to this with React when setting state and using map
.
In this case I was making an API fetch call and the value of the response wasn't known, but should have a value "Answer". I used a custom type for this, but because the value could be null
, I got a TS error anyway. Allowing the type to be null
doesn't fix it; alternatively you could use a default parameter value
, but this was messy for my case.
I overcame it by providing a default value in the event the response was empty by just using a ternary operator:
this.setState({ record: (response.Answer) ? response.Answer : [{ default: 'default' }] });
Try to call object like this:
(<any>Object).dosomething
This error has come because you have declared them as optional using ?
. Now Typescript does strict check and it won't allow doing anything that may be undefined
. Therefore, you can use (<any>yourObject)
here.
In typescript you can do the following to suppress the error
:
let subString?: string;
subString > !null;
- Note the added exclamation mark before null.
This is not an answer for the OP but I've seen a lot of people confused about how to avoid this error in the comments. This is a simple way to pass the compiler check
if (typeof(object) !== 'undefined') {
// your code
}
Note: This won't work
if (object !== undefined) {
// your code
}
This is rather verbose and don't like it but it's the only thing that worked for me:
if (inputFile && inputFile.current) {
((inputFile.current as never) as HTMLInputElement).click()
}
only
if (inputFile && inputFile.current) {
inputFile.current.click() // also with ! or ? didn't work
}
didn't work for me. Typesript version: 3.9.7 with eslint and recommended rules.
You can use type casting for situations like:
// `textarea` is guaranteed to be loaded
const textarea = <HTMLTextAreaElement>document.querySelector('textarea')
👇 no error here
textarea.value = 'foo'
querySelector()
.
Pretty surprised no one answered this, all you got to do is check if the object exists before accessing it, it's pretty straight forward. Otherwise, make sure you initialize the values that your before accessing the object.
if($protected.listEle.classList) { $protected.listEle.classList.add('visible'); }
Bind you variable like this variabalName?.value
It will work for sure.
Property 'value' does not exist on type 'never'.
Not OPs problems but I fixed this by adding a null check
I changed:
*ngIf="username.invalid && username.errors.required"
To
*ngIf="username.invalid && username.errors != null && username.errors.required"
In angular, I use:
// 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);
Since just using @ts-ignore, the eslint complains that it disables compilation errors, this is why I add the eslint-disable-next-line.
When I changed "strict:true" to "strict:false" in tsconfig.json file than code isn't showing error. add added ! sign with obj like added
myImage!.getAttriute('src');
than code isn't showing error.
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
I had this problem with Angular (11.x). On a previous day I moved a piece of HTML/component to a individual - smaller - component. On the next day my computer had shut down and my project couldn't build. It turned out that the component .html was the problem. So as said, it's the null safety...
From this (excerpt):
<div class="code mat-body-strong">{{ machine.productCode }}</div>
To this:
<div class="code mat-body-strong">{{ machine?.productCode }}</div>
In typescript, to mute message about possibility null:
Interface {
data: string|null
}
const myData = document.data ?? "";
Success story sharing
! - Non-null assertion operator
operator. It seems that the thing is not well documented yet (https://github.com/Microsoft/TypeScript/issues/11494) so anyone looking answers read this http://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-method!
operator here does not do the same thing as?
in C# does! It is only a type system assertion; it will not cause your program to not crash when attempting to read a property fromnull
orundefined
.!
:identifier!
removesnull
andundefined
from the type ofidentifier
This is what Ryan already said, but I find this way helpful too.