[typescript] Does Typescript support the ?. operator? (And, what's it called?)

Does Typescript currently (or are there plans to) support the safe navigation operator of ?.

ie:

var thing = foo?.bar
// same as:
var thing = (foo) ? foo.bar : null;

Also, is there a more common name for this operator (it's incedibly hard to google for).

This question is related to typescript

The answer is


Update: Yes its supported now!

It just got released with TypeScript 3.7 : https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/

It is called optional chaining : https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/#optional-chaining

With it the following:

let x = foo?.bar.baz(); 

is equivalent to:

let x = (foo === null || foo === undefined) ?
    undefined :
    foo.bar.baz();

Old answer

There is an open feature request for this on github where you can voice your opinion / desire : https://github.com/Microsoft/TypeScript/issues/16


_.get(obj, 'address.street.name') works great for JavaScript where you have no types. But for TypeScript we need the real Elvis operator!


As answered before, it's currently still being considered but it has been dead in the water for a few years by now.

Building on the existing answers, here's the most concise manual version I can think of:

jsfiddle

function val<T>(valueSupplier: () => T): T {
  try { return valueSupplier(); } catch (err) { return undefined; }
}

let obj1: { a?: { b?: string }} = { a: { b: 'c' } };
console.log(val(() => obj1.a.b)); // 'c'

obj1 = { a: {} };
console.log(val(() => obj1.a.b)); // undefined
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

obj1 = {};
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

obj1 = null;
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

It simply silently fails on missing property errors. It falls back to the standard syntax for determining default value, which can be omitted completely as well.


Although this works for simple cases, if you need more complex stuff such as calling a function and then access a property on the result, then any other errors are swallowed as well. Bad design.

In the above case, an optimized version of the other answer posted here is the better option:

jsfiddle

function o<T>(obj?: T, def: T = {} as T): T {
    return obj || def;
}

let obj1: { a?: { b?: string }} = { a: { b: 'c' } };
console.log(o(o(o(obj1).a)).b); // 'c'

obj1 = { a: {} };
console.log(o(o(o(obj1).a)).b); // undefined
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

obj1 = {};
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

obj1 = null;
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

A more complex example:

o(foo(), []).map((n) => n.id)

You can also go the other way and use something like Lodash' _.get(). It is concise, but the compiler won't be able to judge the validity of the properties used:

console.log(_.get(obj1, 'a.b.c'));

I don't generally recommend this approach (watch out for performance concerns), but you can use the spread operator to shallow clone an object, which you can then access the property on.

 const person = { personId: 123, firstName: 'Simon' };
 const firstName = { ...person }.firstName;

This works because the type of 'firstName' is 'propagated' through.

I'll use this most frequently when I have a find(...) expression that can return null and I need a single property from it:

 // this would cause an error (this ID doesn't exist)
 const people = [person];
 const firstName2 = people.find(p => p.personId == 999).firstName;

 // this works - but copies every property over so raises performance concerns
 const firstName3 = { ...people.find(p => p.personId == 999) }.firstName;

There may be some edge cases with the way typescript infers types and this won't compile, but this should generally work.


It's finally here!

Here are a few examples:

// properties
foo?.bar
foo?.bar()
foo?.bar.baz()
foo?.bar?.baz()

// indexing
foo?.[0]
foo?.['bar']

// check if a function is defined before invoking
foo?.()
foo.bar?.()
foo?.bar?.()

But it doesn't work exactly the same as your assumption.

Instead of evaluating

foo?.bar

to this little code snippet we are all used to writing

foo ? foo.bar : null

it actually evaluates to

(foo === null || foo === undefined) ?
    undefined :
    foo.bar

which works for all the falsey values like an empty string, 0 or false.

I just don't have an explanation as to why they don't compile it to foo == null


Edit Nov. 13, 2019!

As of November 5, 2019 TypeScript 3.7 has shipped and it now supports ?. the optional chaining operator !!!

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining


For Historical Purposes Only:

Edit: I have updated the answer thanks to fracz comment.

TypeScript 2.0 released !. It's not the same as ?.(Safe Navigator in C#)

See this answer for more details:

https://stackoverflow.com/a/38875179/1057052

This will only tell the compiler that the value is not null or undefined. This will not check if the value is null or undefined.

TypeScript Non-null assertion operator

// Compiled with --strictNullChecks
function validateEntity(e?: Entity) {
    // Throw exception if e is null or invalid entity
}

function processEntity(e?: Entity) {
    validateEntity(e);
    let s = e!.name;  // Assert that e is non-null and access name
}

This is defined in the ECMAScript Optional Chaining specification, so we should probably refer to optional chaining when we discuss this. Likely implementation:

const result = a?.b?.c;

The long and short of this one is that the TypeScript team are waiting for the ECMAScript specification to get tightened up, so their implementation can be non-breaking in the future. If they implemented something now, it would end up needing major changes if ECMAScript redefine their specification.

See Optional Chaining Specification

Where something is never going to be standard JavaScript, the TypeScript team can implement as they see fit, but for future ECMAScript additions, they want to preserve semantics even if they give early access, as they have for so many other features.

Short Cuts

So all of JavaScripts funky operators are available, including the type conversions such as...

var n: number = +myString; // convert to number
var b: bool = !!myString; // convert to bool

Manual Solution

But back to the question. I have an obtuse example of how you can do a similar thing in JavaScript (and therefore TypeScript) although I'm definitely not suggesting it is a graceful as the feature you are really after.

(foo||{}).bar;

So if foo is undefined the result is undefined and if foo is defined and has a property named bar that has a value, the result is that value.

I put an example on JSFiddle.

This looks quite sketchy for longer examples.

var postCode = ((person||{}).address||{}).postcode;

Chain Function

If you are desperate for a shorter version while the specification is still up in the air, I use this method in some cases. It evaluates the expression and returns a default if the chain can't be satisfied or ends up null/undefined (note the != is important here, we don't want to use !== as we want a bit of positive juggling here).

function chain<T>(exp: () => T, d: T) {
    try {
        let val = exp();
        if (val != null) {
            return val;
        }
    } catch { }
    return d;
}

let obj1: { a?: { b?: string }} = {
    a: {
        b: 'c'
    }
};

// 'c'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = {
    a: {}
};

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = {};

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = null;

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

It's called optional chaining and It's in Typescript 3.7

Optional chaining lets us write code where we can immediately stop running some expressions if we run into a null or undefined


Not yet (as of September, 2019), but since the "safe navigation operator" is now at Stage 3, it's being implemented in TypeScript.

Watch this issue for updates:

https://github.com/microsoft/TypeScript/issues/16

Several engines have early implementations:

JSC: https://bugs.webkit.org/show_bug.cgi?id=200199

V8: https://bugs.chromium.org/p/v8/issues/detail?id=9553

SM: https://bugzilla.mozilla.org/show_bug.cgi?id=1566143

(via https://github.com/tc39/proposal-optional-chaining/issues/115#issue-475422578)

You can install a plugin to support it now:

npm install --save-dev ts-optchain

In your tsconfig.json:

// tsconfig.json
{
    "compilerOptions": {
        "plugins": [
            { "transform": "ts-optchain/transform" },
        ]
    },
}

I expect this answer to be out of date in the next 6 months or so, but hopefully it will help someone in the meantime.


We created this util method while working on Phonetradr which can give you type-safe access to deep properties with Typescript:

_x000D_
_x000D_
/**_x000D_
 * Type-safe access of deep property of an object_x000D_
 *_x000D_
 * @param obj                   Object to get deep property_x000D_
 * @param unsafeDataOperation   Function that returns the deep property_x000D_
 * @param valueIfFail           Value to return in case if there is no such property_x000D_
 */_x000D_
export function getInSafe<O,T>(obj: O, unsafeDataOperation: (x: O) => T, valueIfFail?: any) : T {_x000D_
    try {_x000D_
        return unsafeDataOperation(obj)_x000D_
    } catch (error) {_x000D_
        return valueIfFail;_x000D_
    }_x000D_
}_x000D_
_x000D_
//Example usage:_x000D_
getInSafe(sellTicket, x => x.phoneDetails.imeiNumber, '');_x000D_
_x000D_
//Example from above_x000D_
getInSafe(foo, x => x.bar.check, null);
_x000D_
_x000D_
_x000D_


Operator ?. is not supported in TypeScript version 2.0.

So I use the following function:

export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
    if (typeof someObject === 'undefined' || someObject === null)
        return defaultValue;
    else
        return someObject;
}

the usage looks like this:

o(o(o(test).prop1).prop2

plus, you can set a default value:

o(o(o(o(test).prop1).prop2, "none")

It works really well with IntelliSense in Visual Studio.


The Elvis (?.) Optional Chaining Operator is supported in TypeScript 3.7.

You can use it to check for null values: cats?.miows returns null if cats is null or undefined.

You can also use it for optional method calling: cats.doMiow?.(5) will call doMiow if it exists.

Property access is also possible: cats?.['miows'].

Reference: https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-beta/


Not as nice as a single ?, but it works:

var thing = foo && foo.bar || null;

You can use as many && as you like:

var thing = foo && foo.bar && foo.bar.check && foo.bar.check.x || null;