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).
property ?? property2
, but if you tried property.company ?? property1.company
and property
was null, you'd get a NullReferenceException
v3.7
and it's called Optional Chaining
. See my answer for code examples.
Yes. As of TypeScript 3.7 (released on November 5, 2019), this feature is supported and is called Optional Chaining:
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.
Refer to the TypeScript 3.7 release notes for more details.
Prior to version 3.7, this was not supported in TypeScript, although it was requested as early as Issue #16 on the TypeScript repo (dating back to 2014).
As far as what to call this operator, there doesn't appear to be a consensus. In addition to "optional chaining" (which is also what it's called in JavaScript and Swift), there are a couple of other examples:
CoffeeScript refers to it as the existential operator (specifically, the "accessor variant" of the existential operator):
The accessor variant of the existential operator ?. can be used to soak up null references in a chain of properties. Use it instead of the dot accessor . in cases where the base value may be null or undefined.
C# calls this a null-conditional operator.
a null-conditional operator applies a member access, ?., or element access, ?[], operation to its operand only if that operand evaluates to non-null; otherwise, it returns null.
Kotlin refers to it as the safe call operator.
There are probably lots of other examples, too.
It is now possible, see answer of user "Donut".
Old answer: Standard JavaScript behaviour regarding boolean operators has something that may help. The boolean methods do not return true or false when comparing objects, but in case of OR the first value that is equal to true.
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;
Default values are also possible:
var name = person && person.name || "Unknown user";
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'));
(this.loop || {}).nativeElement
saying Property 'nativeElement' does not exist on type '{}'. any
this.loop
typeof angular.io/api/core/ElementRef
{}
, or 2) use a type assertion to silence the compiler.
foo
is an actual useful object : (foo || {}).bar
generally isn't going to compile in typescript because {}
won't be of the same type as foo
. That's the problem that @VeganHunter's solution aims to avoid.
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
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
}
?
because it asserts that the value is defined. ?
is expected to silently fail / evaluate to false. Anyway, good to know.
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/
?:
. Do you have a reference?
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
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.
elvis<T>
;-)
We created this util method while working on Phonetradr which can give you type-safe access to deep properties with Typescript:
/**
* Type-safe access of deep property of an object
*
* @param obj Object to get deep property
* @param unsafeDataOperation Function that returns the deep property
* @param valueIfFail Value to return in case if there is no such property
*/
export function getInSafe
return this.entry.fields.featuredImage.fields.file.url;
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 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
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:
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:
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'));
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.
I think this is what you're looking for. Similiar example at Powerbite
/**
* Type-safe access of deep property of an object
*
* @param obj Object to get deep property
* @param unsafeDataOperation Function that returns the deep property
* @param valueIfFail Value to return in case if there is no such property
*/
export function getInSafe<O,T>(obj: O, unsafeDataOperation: (x: O) => T, valueIfFail?: any) : T {
try {
return unsafeDataOperation(obj)
} catch (error) {
return valueIfFail;
}
}
//Example usage:
getInSafe(sellTicket, x => x.phoneDetails.imeiNumber, '');
//Example from above
getInSafe(foo, x => x.bar.check, null);
_.get(obj, 'address.street.name')
works great for JavaScript where you have no types. But for TypeScript we need the real Elvis operator!
Success story sharing