Optional chaining ?. is safer to use than non-null assertions !.

Consider the following interface:

interface Foo {
    bar?: {
        baz: string;
    }
}

The bar property is optional. If it doesn't exist it will be undefined when you read it. If it does exist it will have a baz property of type string. If you just try to access the baz property without making sure that bar is defined, you'll get a compiler error warning you about a possible runtime error:

function oops(foo: Foo) {
    console.log(foo.bar.baz.toUpperCase()); // compiler error
    // -------> ~~~~~~~
    // Object is possibly undefined
}

Optional chaining has actual effects at runtime and short-circuits to an undefined value if the property you're trying to access does not exist. If you don't know for sure that a property exists, optional chaining can protect you from some runtime errors. The TypeScript compiler does not complain with the following code because it knows that what you are doing is now safe:

function optChain(foo: Foo) {
    console.log(foo.bar?.baz.toUpperCase());
}

optChain({ bar: { baz: "hello" } }); // HELLO
optChain({}); // undefined

You should use optional chaining if you are not sure that your property accesses are safe and you want runtime checks to protect you.


On the other hand, non-null assertions have no effect whatsoever at runtime. It's a way for you to tell the compiler that even though it cannot verify that a property exists, you are asserting that it is safe to do it. This also has the effect of stopping the compiler from complaining, but you have now taken over the job of ensuring type safety. If, at runtime, the value you asserted as defined is actually undefined, then you have lied to the compiler and you might hit a runtime error:

function nonNullAssert(foo: Foo) {
    console.log(foo.bar!.baz.toUpperCase());
}

nonNullAssert({ bar: { baz: "hello" } }); // HELLO
nonNullAssert({}); //  TypeError: foo.bar is undefined

You should only use non-null assertions if you are sure that your property accesses are safe, and you want the convenience of skipping runtime checks.


Playground link to code

Answer from jcalz on Stack Overflow
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Operators › Optional_chaining
Optional chaining (?.) - JavaScript | MDN
The optional chaining (?.) operator accesses an object's property or calls a function. If the object accessed or function called using this operator is undefined or null, the expression short circuits and evaluates to undefined instead of throwing an error.
🌐
TypeScript
typescriptlang.org › docs › handbook › release-notes › typescript-3-7.html
TypeScript: Documentation - TypeScript 3.7
At its core, optional chaining lets us write code where TypeScript can immediately stop running some expressions if we run into a null or undefined. The star of the show in optional chaining is the new ?. operator for optional property accesses.
Discussions

Should we use ! (non-null assertion) or ?. (optional chaining) in TypeScript?
On the other hand, ?. is used to prevent errors when no property found and instead returns undefined. In the above example, I can use either ! or ?. or even both of them combined !?., and Typescript compiler does not complain. So which one is best and safest to use? ... Optional chaining ?. More on stackoverflow.com
🌐 stackoverflow.com
How to enforce the use of optional chaining for any type object in TypeScript?
Strict null checks option But also using unknown instead of any And maybe there’s a typescript eslint lint rule but the type checking system is usually good enough here More on reddit.com
🌐 r/typescript
24
1
June 20, 2024
Using optional chaining operator for object property access
TypeScript 3.7 now supports the optional chaining operator. Hence, you can write code such as: const value = a?.b?.c; I.e., you can use this operator to access properties of an object, where the o... More on stackoverflow.com
🌐 stackoverflow.com
[AskJS] Is it a problem if the code base is filled with optional chaining?
A mantra in the Zig community that is applicable here: "Handled errors are better than exceptions, but exceptions are better than bugs" More on reddit.com
🌐 r/javascript
43
15
July 17, 2024
🌐
DEV Community
dev.to › jesterxl › avoid-optional-chaining-and-optional-properties-5d4b
Avoid Optional Chaining and Optional Properties - DEV Community
April 21, 2025 - It’s clear many JavaScript/TypeScript developers who utilize optional chaining like “thing | undefined”, or worse optional properties, “property?: thing | undefined” haven’t learned this painful lesson. It may look flexible, having multiple classes/functions capable of handling ...
🌐
TypeScript
typescriptlang.org › play › 3-7 › syntax-and-messaging › optional-chaining.ts
TypeScript: Playground Example - Optional Chaining
TypeScript · in En · Optional chaining reached TC39 Stage 3 consensus during 3.7's development. Optional Chaining allows you to write code which can immediately stop running expressions when it hits a null or undefined. Property Access Let's imagine we have an album where the artist, and ...
Top answer
1 of 2
16

Optional chaining ?. is safer to use than non-null assertions !.

Consider the following interface:

interface Foo {
    bar?: {
        baz: string;
    }
}

The bar property is optional. If it doesn't exist it will be undefined when you read it. If it does exist it will have a baz property of type string. If you just try to access the baz property without making sure that bar is defined, you'll get a compiler error warning you about a possible runtime error:

function oops(foo: Foo) {
    console.log(foo.bar.baz.toUpperCase()); // compiler error
    // -------> ~~~~~~~
    // Object is possibly undefined
}

Optional chaining has actual effects at runtime and short-circuits to an undefined value if the property you're trying to access does not exist. If you don't know for sure that a property exists, optional chaining can protect you from some runtime errors. The TypeScript compiler does not complain with the following code because it knows that what you are doing is now safe:

function optChain(foo: Foo) {
    console.log(foo.bar?.baz.toUpperCase());
}

optChain({ bar: { baz: "hello" } }); // HELLO
optChain({}); // undefined

You should use optional chaining if you are not sure that your property accesses are safe and you want runtime checks to protect you.


On the other hand, non-null assertions have no effect whatsoever at runtime. It's a way for you to tell the compiler that even though it cannot verify that a property exists, you are asserting that it is safe to do it. This also has the effect of stopping the compiler from complaining, but you have now taken over the job of ensuring type safety. If, at runtime, the value you asserted as defined is actually undefined, then you have lied to the compiler and you might hit a runtime error:

function nonNullAssert(foo: Foo) {
    console.log(foo.bar!.baz.toUpperCase());
}

nonNullAssert({ bar: { baz: "hello" } }); // HELLO
nonNullAssert({}); //  TypeError: foo.bar is undefined

You should only use non-null assertions if you are sure that your property accesses are safe, and you want the convenience of skipping runtime checks.


Playground link to code

2 of 2
4

Those are completely different things.

The null assertion operator !. is you, the programmer, asserting to the compiler that you know for a fact that the property access cannot fail for reasons the compiler cannot prove. It is no more safe from a runtime error than any other assertion that you the programmer make to the compiler that you know better that it does.

const foo = null;
foo!.someProperty; // compiles but you will get a TypeError! Cannot read property 'someProperty' of null or undefined.

The other is the optional chaining operator. It is basically shorthand for this common Javascript pattern:

const something = foo && foo.bar && foo.bar.baz;

But it's better than just shorthand, because the above will fail if one of those values is falsey but some falsey values support property access. With the optional property accessor you just write:

const something = foo?.bar?.baz;

And you're done. And just like the Javascript version it's "safe" in that it's guaranteed not to result in a runtime error from trying to access a property of a null reference.

In the particular case you have there, you probably want something like this:

const enteredText = textInputRef.current?.value || '';

Where it's very clear that the result is a string no matter what.

🌐
GeeksforGeeks
geeksforgeeks.org › typescript › how-optional-chaining-works-in-typescript
How optional chaining works in TypeScript ? - GeeksforGeeks
March 22, 2022 - TypeScript Optional Chaining is the process of searching and calling variables, methods, parameters that might be nil in existence.
Find elsewhere
🌐
Reddit
reddit.com › r/typescript › how to enforce the use of optional chaining for any type object in typescript?
r/typescript on Reddit: How to enforce the use of optional chaining for any type object in TypeScript?
June 20, 2024 -

I'm trying to enforce the use of optional chaining for accessing properties of any type object in TypeScript to avoid potential runtime errors. For example, I want the following code to throw a TypeScript error:

    catch(e: any) {
        const code = e.code; // This should throw a TypeScript error
    }

But this code should not throw an error:

    catch(e: any) {
        const code = e?.code; // This should not throw a TypeScript error
    }

Is there a way to configure TypeScript to enforce this rule or any workaround to achieve this behavior?

🌐
Medium
medium.com › @ambily_francis › safely-navigate-objects-with-optional-chaining-in-typescript-878f29d85118
Safely Navigate Objects with Optional Chaining in TypeScript | by Ambily Francis | Medium
March 11, 2024 - Optional chaining in TypeScript is a feature that allows accessing properties or calling methods of an object without the need for null or undefined checks.
🌐
LogRocket
blog.logrocket.com › home › optional chaining and nullish coalescing in typescript
Optional chaining and nullish coalescing in TypeScript - LogRocket Blog
June 4, 2024 - In TypeScript, optional chaining is defined as the ability to immediately stop running an expression if a part of it evaluates to either null or undefined. It was introduced in TypeScript 3.7 with the ?.
🌐
Marius Schulz
mariusschulz.com › blog › optional-chaining-the-operator-in-typescript
Optional Chaining: The ?. Operator in TypeScript — Marius Schulz
September 11, 2021 - TypeScript 3.7 added support for ... use this operator to descend into an object whose properties potentially hold the values null or undefined without writing any null checks for intermediate properties....
🌐
JavaScript.info
javascript.info › tutorial › the javascript language › objects: the basics
Optional chaining '?.'
E.g. in user?.address.street.name the ?. allows user to safely be null/undefined (and returns undefined in that case), but that’s only for user. Further properties are accessed in a regular way. If we want some of them to be optional, then we’ll need to replace more .
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Operators › Nullish_coalescing
Nullish coalescing operator (??) - JavaScript | MDN
The nullish coalescing operator treats undefined and null as specific values. So does the optional chaining operator (?.), which is useful to access a property of an object which may be null or undefined.
🌐
Medium
sanjanahumanintech.medium.com › what-is-optional-chaining-in-typescript-7d6430e79917
What is Optional Chaining in TypeScript? | by Sanjana Human In Tech | Medium
October 30, 2023 - Optional Chaining is a feature in TypeScript that allows you to safely access deeply nested properties and methods of an object or array, without explicitly checking for the existence of each level.
🌐
Datadog
docs.datadoghq.com › code_analysis › static_analysis_rules › typescript-best-practices › prefer-optional-chain
Prefer an optional chain instead of chaining operators
The JavaScript optional chaining operator (?.) allows you to read the value of a property located deep within a chain of connected objects without having to validate that each reference in the chain is valid.
🌐
Valentino G.
valentinog.com › blog › chaining
Using Optional Chaining in TypeScript and JavaScript
February 7, 2020 - What can we do to protect our code from these kind of errors? Let's see how optional chaining helps. Let's get TypeScript to check our code. Rename optional_chaining.js to optional_chaining.ts.
🌐
TypeScript
typescriptlang.org › docs › handbook › advanced-types.html
TypeScript: Documentation - Advanced Types
For a n in x expression, where n is a string literal or string literal type and x is a union type, the “true” branch narrows to types which have an optional or required property n, and the “false” branch narrows to types which have an optional or missing property n. ... Let’s go back ...
Top answer
1 of 3
20

At time of writing, TypeScript does not support the optional chaining operator. See discussion on the TypeScript issue tracker: https://github.com/Microsoft/TypeScript/issues/16

As a warning, the semantics of this operator are still very much in flux, which is why TypeScript hasn't added it yet. Code written today against the Babel plugin may change behavior in the future without warning, leading to difficult bugs. I generally recommend people to not start using syntax whose behavior hasn't been well-defined yet.

2 of 3
12

Update Oct 15, 2019

Support now exists in [email protected]

Say thanks to https://stackoverflow.com/a/58221278/6502003 for the update!


Although TypeScript and the community are in favor of this operator, until TC39 solidifies the current proposal (which at the time of this writing is at stage 1) we will have to use alternatives.

There is one alternative which gets close to optional chaining without sacrificing dev tooling: https://github.com/rimeto/ts-optchain

This article chronicles what the creators were able to achieve in trying to mirror the native chaining operator:

  1. Use a syntax that closely mirrors chained property access
  2. Offer a concise expression of a default value when traversal fails
  3. Enable IDE code-completion tools and compile-time path validation

In practice it looks like this:

import { oc } from 'ts-optchain';

// Each of the following pairs are equivalent in result.
oc(x).a();
x && x.a;

oc(x).b.d('Default');
x && x.b && x.b.d || 'Default';

oc(x).c[100].u.v(1234);
x && x.c && x.c[100] && x.c[100].u && x.c[100].u.v || 1234;

Keep in mind that alternatives like this one will likely be unnecessary once the proposal is adopted by TypeScript.

Also, a big thanks to Ryan Cavanaugh for all the work you are doing in advocating this operator to TC39!