DEV Community

Cover image for Typescript - Tips & Tricks - Non-null assertion operator
Luca Del Puppo for This is Learning

Posted on • Edited on

Typescript - Tips & Tricks - Non-null assertion operator

In some cases, you have a field that you initialize in a method, and if you follow the flow of the code you are sure that this field is initialized but typescript doesn't understand it.
An example

type Person = {
  name: string;
};

let person: Person;

function initialize() {
  person = { name: "name" };
}

initialize();
console.log("Hello", person.name); // Variable 'person' is used before being assigned.
Enter fullscreen mode Exit fullscreen mode

In this case, you can see how the typescript compiler doesn't understand that the "person" field isn't null but it's initialized.
To resolve this problem, the typescript language exposes us the "Non-null assertion operation"(!). This operator says to the compiler that the field isn't null or undefined but it's defined.
The previous example can be reviewed in this way

type Person = {
  name: string;
};

let person: Person;

function initialize() {
  person = { name: "name" };
}

initialize();
console.log("Hello", person!.name);
Enter fullscreen mode Exit fullscreen mode

As you can see, in this case, the code doesn't have errors and the compilation ends with success.

That's all for today!
Bye-bye guys!

Top comments (7)

Collapse
 
jackmellis profile image
Jack

Amazing.

There are many many times that you have 100% confidence in a property's existence, but typescript does not...

Off the top of my head: response data from an api where you know that if property a has a specific value, then property b will not be null.

Another example is if you're using something like jsx-control-statements in react:

<If condition={myObj?.name != null}>
  {myObj.name}
</If>
Enter fullscreen mode Exit fullscreen mode

You can assert that a property exists, but then when you reference it on the next line, typescript is unable to infer from the control statement that myObj is not null.

I come across these issues all the time. I didn't realise this feature existed and I highly expect I'll need to use it at some point before the week is out.

Collapse
 
puppo profile image
Luca Del Puppo

I'm glad I showed you a new feature.
In your first case, you could create different types base on the response type, so you can detect the correct type if some field has or not has a specific value.
I leave you a simple case, I hope it can help you in the future.

type WsResponseOk = {
    value: true
}

type WsResponseError = {
  value: false;
  error: string;
};

type WsResponse = WsResponseOk | WsResponseError;

const getResponse = (): WsResponse => ({ value: true })

let response = getResponse();

if (response.value) {
  // response => WsResponseOk
  response.value;
  response.error; // Property 'error' does not exist on type 'WsResponseOk'.
} else {
  // response => WsResponseError
  response.value;
  response.error;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jackmellis profile image
Jack

Yes I do this but often the combinations are so complex it becomes impractical and often typescript is left unable to correctly infer which variation you're referring to. This is especially true when you're passing an object around several different functions or if you're using assertions that are out of your control that also don't offer sufficient type guarding.

Collapse
 
lyrod profile image
Lyrod

Not a good practice

Collapse
 
puppo profile image
Luca Del Puppo • Edited

I agree with you. With great power comes great responsibility.
In my opinion, I prefer to use the Assert Function instead of the Non-null assertion operator.
But I talk about the Assert functions in a future post.

Collapse
 
davidbrear profile image
David Brear

This feels like a work around for bad coders to avoid fixing their code-smell. If I saw this in code I was working on, Iā€™d change the underlying code to not be bad.

Collapse
 
puppo profile image
Luca Del Puppo

I agree with you. This post has the scope to explain the Non-null assertion operator.
In a real case, maybe you can't change the code behind because it's in an external dependence; in this case, I would prefer to use an Assert Function, but it is a topic of a future post.