519

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?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129

31 Answers31

1122

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;
Willem Renzema
  • 5,177
  • 1
  • 17
  • 24
Ryan Cavanaugh
  • 209,514
  • 56
  • 272
  • 235
  • 33
    Thanks for letting me know about `! - Non-null assertion operator` operator. It seems that the thing is not well documented yet ([https://github.com/Microsoft/TypeScript/issues/11494](https://github.com/Microsoft/TypeScript/issues/11494)) so anyone looking answers read this [http://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-method](http://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-method) –  Nov 01 '16 at 09:42
  • 14
    this also has no effect for me on tsc v2.7.2 – Tyguy7 Apr 06 '18 at 21:41
  • Wow thanks I've been looking for this for so long - I didn't know it existed in JavaScript. The nul check operator works the same in C# but it is a `?` – Thomas Sauvajon Apr 27 '18 at 11:01
  • 7
    @ThomasSauvajon the `!` 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 from `null` or `undefined`. – Ryan Cavanaugh Apr 27 '18 at 14:24
  • 5
    From handbook, added at Ryan's prodding: _The syntax is postfix `!`: `identifier!` removes `null` and `undefined` from the type of `identifier`_ This is what Ryan already said, but I find this way helpful too. – John Hatton Jul 11 '18 at 01:00
  • what version de typescript is needed? – stackdave Nov 22 '18 at 10:24
  • 11
    This does not work in Typescript 3.2.2. Has it been removed? – Lars Nyström Jan 07 '19 at 14:56
  • Works on typescript 3.6.3 as well. Amazing solution when you're working with some libraries like lodash and Typescript doesn't get that the function you use already checks for null/undefined values – Carrm Oct 30 '19 at 07:53
  • @ThomasSauvajon - JavaScript now has `?.` (optional chaining) as part of the ES2020 standard: https://github.com/tc39/proposal-optional-chaining (`?.` [JavaScript] and `!.` [TypeScript] do different things, as Ryan mentioned, but optional chaining is often useful...) – T.J. Crowder Mar 14 '20 at 14:42
  • 2
    ?. = chain this if it isn't null, !. = do this it's definitely not null,welp if it happens to be null I'm screwed – Persk Jun 27 '20 at 02:53
  • I did the same thing in the following line: mapRef.current!.setZoom(expansionZoom); I get "Property 'setZoom' does not exist on type 'never'. TS2339". @RyanCavanaugh – Mahagney Saleh Oct 23 '20 at 07:16
  • 2
    I wouldn't recommend this in general. The compiler is telling you it can't prove something is not null. You are telling it "believe me, it isn't". It's better to actually convince the compiler something isn't null rather than suppressing its complaints. – siride Mar 19 '22 at 17:53
  • @siride if I have getter like this `get addressForm(): FormGroup { return this.p.parentForm['controls'].address as FormGroup; }` and then reference tons of this form's fields - I do not want to see hundreds of syntax error highlight nightmare in my typescript page. I want to let language analyzer know i'm sure it is not null. Unfortunately, even putting `!` is not always enough to get rid of these "smart" error messages... – Alexander Jul 22 '22 at 13:37
  • @Alexander You could make a helper method that validates a given field with a null check (throws exception if null or undefined) and then use that throughout your code. But I reiterate what I said: you need to prove to the compiler that your fields are not null. It can't know unless you do the work. – siride Jul 22 '22 at 17:28
  • Getting `Forbidden Non-null assertion` error after trying this. – Srk95 Aug 16 '23 at 07:01
  • Sounds like a lint rule – Ryan Cavanaugh Aug 16 '23 at 16:29
192

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!

Vlad Topala
  • 896
  • 1
  • 8
  • 34
Douglas
  • 36,802
  • 9
  • 76
  • 89
  • 9
    Personally I use `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. –  Nov 01 '16 at 09:50
  • 59
    Even initialization doesn't suppress "Object is possibly 'undefined'" for me in TS 2.7.2 – Tyguy7 May 23 '18 at 18:00
  • 1
    Yes, but these definitions change the values of the objects, for example, HTMLDivElement doesn't have closest target and other basic element events and properties. – Clarence Sep 13 '18 at 19:54
  • 8
    What if you are trying to describe a state of some Javascript Object property, where the true representation of the starting state is `null`? – Tim Dec 06 '18 at 16:56
  • 1
    Adding that there's a `!` operator available, very similar to the ones in Kotlin that lets you make these checks much more concise – Alvaro Jun 27 '19 at 22:54
  • 1
    The non-null assertion operator (`!`) is not a "check", it's kind of the opposite of a check. You're saying that, for reasons impossible to express through the existing type system, your reference to a property that's been declared as possibly-null-or-undefined, absolutely definitely cannot be at this point in program execution -- basically, that you know better than the compiler. – Coderer Sep 10 '20 at 14:54
  • this rule is annoying in unit tests where you want to fail if it is null anyway (and using ? operators will suppress the failure!) – java-addict301 Nov 22 '21 at 19:36
94

Option 1 - Suppressing

You can suppress the compiler error 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 doesn't work. Also, as per the documentation, this should be used rarely, only when necessary

Option 2 - Optional chaining

With Typescript 3.7 onwards, optional chaining might be applicable in some cases

refToElement?.current?.focus();

But again, only if it's really needed, as in some cases the error might actually point to a bigger problem -

Option 3 - Passing the right type

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);
Vandesh
  • 6,368
  • 1
  • 26
  • 38
  • 3
    Much better solution than disabling the `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. – Andy Braham Oct 16 '19 at 05:38
  • 2
    Property 'getBoundingClientRect' does not exist on type 'never'. – mqliutie May 05 '20 at 02:12
  • 5
    In my case this optional chaining did not work. `const input = useRef(null);` and `if (input && input.current) { input.current.value = ''; }` did the trick. – Timo May 18 '20 at 15:37
  • 4
    Property 'goBack' does not exist on type 'never'.ts(2339) – Rishav Kumar Sep 21 '20 at 15:18
  • You need to specify the component type in `useRef(null)`, otherwise TS doesn't know that the reference can also be something else than `null`. – User Rebo Feb 16 '21 at 15:43
  • the comment `//@ts-ignore ` has to be placed just before the line producing the error – Ashique Razak Sep 29 '21 at 17:40
72

This solution worked for me:

  • go to tsconfig.json and add "strictNullChecks":false

enter image description here

Mahesh Nepal
  • 1,385
  • 11
  • 16
  • 1
    This worked for me as well. Although its still giving error like, for example in subscribe statements, it is not recognizing result variable, typescript wants it to declare .subscribe(result => this.result =result.json()); – Aarchie Jan 29 '18 at 18:59
  • Have you tried using 'map' operator? Google 'rxjs/map'. I basically do:. Http.get(...).map(result => result.json()).subscribe(result=>{do your stuff here}) – Mahesh Nepal Jan 31 '18 at 16:39
  • 72
    doesn't answer the question. OP explicitly said: 'without disabling TS compiler checks' – pvill Mar 24 '18 at 15:13
  • 10
    What the point using TypeScript and removing the linter error aim to alert you? I think the better option is to cast the desired value with `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 – Vincent Dec 07 '18 at 11:26
  • @Vincent the point is to get intelligent auto-complete in your IDE while still retaining some of the dynamic nature of JavaScript. – Martin Sotirov May 25 '21 at 14:44
  • @MartinSotirov Agree but back in 2018, it was not working at intended :) – Vincent May 27 '21 at 08:25
59

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.

JoshuaTree
  • 1,211
  • 14
  • 19
  • 101
    for some reason my TSC ignores that if statement, still considers it to possibly be undefined... – Tyguy7 Apr 06 '18 at 21:40
  • 18
    my error is NOT supressed when I use `if(object!==undefined) object.function();` – Jérémy Mar 06 '19 at 07:27
  • One can also use double comparison with `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` – Marecky Apr 04 '19 at 08:39
  • 3
    Also does not suppress the error for me with a recent typescript. Any workarounds for this frustrating behavior? – jeremyong Jul 15 '20 at 23:55
  • I have to use ! or ? nowdays, even though finding the documentation on this is difficult. What is these operators called? – JoshuaTree Jul 29 '20 at 08:14
  • Also the type casting mentioned above works. – JoshuaTree Dec 23 '20 at 11:08
  • Also consider giving `myobject` a possible type `const myobject: MyObject | null = null`, if its only assigned to null / undefined. @JoshuaTree it's called [optional chaining](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining) – User Rebo Feb 16 '21 at 15:53
  • 1
    the checks don't seem to be supressing my warning, and the object concerned here is `this` ! – Paulo Apr 05 '21 at 02:42
  • @Jérémy That's because you also have to check for `null`. – siride Jul 22 '22 at 17:31
36

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
Ericgit
  • 6,089
  • 2
  • 42
  • 53
  • 4
    I'd say this is the right answer, although already posted above. I think answers suggesting a change in consumer code are just wrong. – adi518 Aug 01 '20 at 22:32
  • 1
    above may crash at run time, best would be check, ```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 – Furquan Mar 02 '21 at 20:08
19

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.

ssube
  • 47,010
  • 7
  • 103
  • 140
  • 2
    "compiler is doing exactly what you're asking it to" so my idea is wrong, thanks. I need to change approach a little. –  Nov 01 '16 at 09:51
  • In my case the compiler simply didn't realize that I already checked the object for null. I have a getter that checks for null and call that getter. So no, it's not doing exactly what I asked it (this is not to say I expect it to figure everything out) to. – CWagner Mar 27 '19 at 08:57
17

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;
thinkOfaNumber
  • 2,581
  • 3
  • 27
  • 46
  • 5
    This is the actual answer. Frustrating when you do an actual explicit null check and still get `Object is possibly 'null'` error. This answer solves that. – Ben Racicot Jun 29 '19 at 21:27
14

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.

Shevchenko Viktor
  • 5,206
  • 2
  • 17
  • 26
  • this was the working solution for me. Declaring that member as type 'any' in an 'on fly' interface has solved the problem – Botea Florin Sep 07 '20 at 05:03
  • @BoteaFlorin You should not cast it to `any`. Instead cast it to an explicit type. If you use `any` you miss the point of using TypeScript in the first place. – Martin Braun Jan 13 '21 at 20:03
  • A practical example of casting to suppress the null possibility is `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) – Ahmed Shaqanbi Dec 26 '21 at 14:41
  • @AhmedShaqanbi that's not a good example. You should still check, or use option chaining. If the compiler thinks something could be null, then it really probably can be and you should write code under the assumption. – siride Mar 19 '22 at 17:58
13

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
}
  • 4
    It's not a good idea to turn this off. The rule is there to help you avoid a very common class of type errors. It's better to fix your program (adjust types and add if checks) than to silence annoying but useful errors. – siride Mar 19 '22 at 17:59
  • 4
    Turning off "strictNullChecks" is not a solution. – Mitul Verma May 18 '22 at 17:05
9

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

Jamie Hutber
  • 26,790
  • 46
  • 179
  • 291
5

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.

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • I don't recommend doing this everywhere, but I'll do this sometimes - especially if relying on @Input parameters set from the outside – Simon_Weaver Jan 24 '19 at 19:05
5

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
    }
Gedeon
  • 742
  • 9
  • 13
5

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
3

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' }] });
3

You can use type casting for situations like:

// when `textarea` is guaranteed to be loaded
const textarea = <HTMLTextAreaElement>document.querySelector('textarea')
 no error here
textarea.value = 'foo'
Wenfang Du
  • 8,804
  • 9
  • 59
  • 90
2

In typescript you can do the following to suppress the error:

let subString?: string;

subString > !null; - Note the added exclamation mark before null.

Philipp Meissner
  • 5,273
  • 5
  • 34
  • 59
user3834142
  • 551
  • 4
  • 8
2

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.

Pedro Mutter
  • 1,178
  • 1
  • 13
  • 18
2

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
    }
Joe
  • 33
  • 5
2

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.

mosu
  • 587
  • 2
  • 8
  • 20
2
// @ts-nocheck

Add this to the top of the file

enter image description here

Santosh nayak
  • 201
  • 3
  • 8
2

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');
}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Ahmad Khudeish
  • 1,017
  • 13
  • 15
2

Bind you variable like this variabalName?.value It will work for sure.

Vibhu kumar
  • 386
  • 3
  • 8
2
  1. When I changed "strict:true" to "strict:false" in tsconfig.json file than code isn't showing error.

  2. add added ! sign with obj like added

    myImage!.getAttriute('src');
    

than code isn't showing error.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
2

Note: it might not be a recommended action - maybe the solution is to actually address the errors. All the checks are in place for a reason, so disabling them is not always the right thing to do, but...

a similar answer to some of the above, but a little bit different in the end. I've had an issue with multiple different checks and what helped me was setting a strict property to false in tsconfig.json. Seems like a more generic variation of the specific checks mentioned above.

  "compilerOptions": {
    "strict": false
  },
Duck Ling
  • 1,577
  • 13
  • 20
1

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"
Nick
  • 3,217
  • 5
  • 30
  • 42
1

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.

Shmarkus
  • 178
  • 1
  • 11
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>

the unique code that works to me using next.js enter image description here

Emanuel
  • 2,603
  • 22
  • 24
0

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>

O-9
  • 1,626
  • 16
  • 15
0

In typescript, to mute message about possibility null:

Interface   {
  data: string|null
}

const myData = document.data ?? "";
dawid debinski
  • 392
  • 4
  • 6
0

this can also be resolved using -> optional chaining (?.) operator for example :

<h2>Price : {{productDetail?.productPrice}}</h2>

if the object 'productDetail' is possible undefined .

jmoerdyk
  • 5,544
  • 7
  • 38
  • 49